Java https代理(使用https.proxyPort和https.proxyHost)

我正在制作一个依赖于设置http.proxyPorthttp.proxyHost的Java应用程序。 有两个过程:一个是常规程序,另一个是代理。 我有一个在http.proxyPort运行的简单套接字监听http.proxyPort (我控制)。 这很简单

 while (true) { try { Socket connection = server.accept(); Handler handler = new Handler(connection); handler.start(); } catch (Exception ex) { ex.printStackTrace(); } } 

所以每当“进程1”发出一个http请求时 – 就像

 URL yahoo = new URL("http://www.google.ca/"); URLConnection yc = yahoo.openConnection(); System.out.println(yc.getClass().getName()); BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream())); 

它通过代理。 现在如果客户端使用HTTPS协议怎么办? 比如使用https://google.ca ? 有一个属性https.proxyPorthttps.proxyHost ,但我确实已经尝试了几个月(开启和关闭,它不是太重要)没有运气。 我已经阅读了一堆线程(我会在最后列出一些,所以你知道我已经做了一些事情)。

我迄今为止最接近的尝试:服务器

 try { System.setProperty("javax.net.ssl.keyStore", "test.jks"); System.setProperty("javax.net.ssl.keyStorePassword", "2520xe"); SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); SSLServerSocket sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(9999); System.out.println("Ready"); SSLSocket sslsocket = (SSLSocket) sslserversocket.accept(); InputStream inputstream = sslsocket.getInputStream(); InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); OutputStream toClient = sslsocket.getOutputStream(); toClient.write(("HTTP/1.0 200 Connection established\n" + "Content-Length: " + "Shut down!".getBytes().length + "\r\n").getBytes("utf-8")); toClient.write("Shut down!".getBytes("utf-8")); toClient.close(); } catch (Exception exception) { exception.printStackTrace(); } 

客户

 try { System.setProperty("https.proxyHost", "127.0.0.1"); System.setProperty("https.proxyPort", "9999"); URL yahoo = new URL("https://www.google.ca/"); URLConnection yc = yahoo.openConnection(); System.out.println(yc.getClass().getName()); BufferedReader in = new BufferedReader( new InputStreamReader( yc.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine); in.close(); } catch (Exception ex) { ex.printStackTrace(); } 

我得到这个错误javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? 我用谷歌搜索了它,但是想出了一些邮件。

基本上,我需要创建一个java代理服务器,它通过https.proxyPorthttps.proxyHost标志设置到客户端,并且可以将数据发送回客户端应用程序,这可能不会以任何方式进行修改(它只是使用URL connection = new URL("https://...")

我试过的几个网站……

  • 创建一个接受HTTPS的Java代理服务器
  • http://stilius.net/java/java_ssl.php
  • 让Java接受所有证书还有其他的东西,但我找不到任何链接。 我有代码,但是我遇到的错误多于我现在正在做的事情,但如果有帮助我可以加入它(我最初没有,因为这已经是一个很长的问题了)

正如auntyellow评论的那样:你不需要自己做任何SSL摆弄。 基本上,https-proxying是关于在两方之间转发二进制数据。

引用draft-luotonen-web-proxy-tunneling-01.txt :

  CLIENT -> SERVER SERVER -> CLIENT -------------------------------------- ----------------------------------- CONNECT home.netscape.com:443 HTTP/1.0 User-agent: Mozilla/4.0 <<< empty line >>> HTTP/1.0 200 Connection established Proxy-agent: Netscape-Proxy/1.1 <<< empty line >>> <<< data tunneling to both directions begins >>> 

所以基本上你需要确保你信任你的客户足以从你的代理防火墙位置连接到给定的主机和端口。 由于这种常见做法是将允许端口限制为443,拒绝与localhost和“不可信”方的连接。

这是一个“简单”的服务器,如果你不相信,它可以用作Java中的https.proxy

 import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created for http://stackoverflow.com/q/16351413/1266906. */ public class Server extends Thread { public static void main(String[] args) { (new Server()).run(); } public Server() { super("Server Thread"); } @Override public void run() { try (ServerSocket serverSocket = new ServerSocket(9999)) { Socket socket; try { while ((socket = serverSocket.accept()) != null) { (new Handler(socket)).start(); } } catch (IOException e) { e.printStackTrace(); // TODO: implement catch } } catch (IOException e) { e.printStackTrace(); // TODO: implement catch return; } } public static class Handler extends Thread { public static final Pattern CONNECT_PATTERN = Pattern.compile("CONNECT (.+):(.+) HTTP/(1\\.[01])", Pattern.CASE_INSENSITIVE); private final Socket clientSocket; private boolean previousWasR = false; public Handler(Socket clientSocket) { this.clientSocket = clientSocket; } @Override public void run() { try { String request = readLine(clientSocket); System.out.println(request); Matcher matcher = CONNECT_PATTERN.matcher(request); if (matcher.matches()) { String header; do { header = readLine(clientSocket); } while (!"".equals(header)); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(clientSocket.getOutputStream(), "ISO-8859-1"); final Socket forwardSocket; try { forwardSocket = new Socket(matcher.group(1), Integer.parseInt(matcher.group(2))); System.out.println(forwardSocket); } catch (IOException | NumberFormatException e) { e.printStackTrace(); // TODO: implement catch outputStreamWriter.write("HTTP/" + matcher.group(3) + " 502 Bad Gateway\r\n"); outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n"); outputStreamWriter.write("\r\n"); outputStreamWriter.flush(); return; } try { outputStreamWriter.write("HTTP/" + matcher.group(3) + " 200 Connection established\r\n"); outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n"); outputStreamWriter.write("\r\n"); outputStreamWriter.flush(); Thread remoteToClient = new Thread() { @Override public void run() { forwardData(forwardSocket, clientSocket); } }; remoteToClient.start(); try { if (previousWasR) { int read = clientSocket.getInputStream().read(); if (read != -1) { if (read != '\n') { forwardSocket.getOutputStream().write(read); } forwardData(clientSocket, forwardSocket); } else { if (!forwardSocket.isOutputShutdown()) { forwardSocket.shutdownOutput(); } if (!clientSocket.isInputShutdown()) { clientSocket.shutdownInput(); } } } else { forwardData(clientSocket, forwardSocket); } } finally { try { remoteToClient.join(); } catch (InterruptedException e) { e.printStackTrace(); // TODO: implement catch } } } finally { forwardSocket.close(); } } } catch (IOException e) { e.printStackTrace(); // TODO: implement catch } finally { try { clientSocket.close(); } catch (IOException e) { e.printStackTrace(); // TODO: implement catch } } } private static void forwardData(Socket inputSocket, Socket outputSocket) { try { InputStream inputStream = inputSocket.getInputStream(); try { OutputStream outputStream = outputSocket.getOutputStream(); try { byte[] buffer = new byte[4096]; int read; do { read = inputStream.read(buffer); if (read > 0) { outputStream.write(buffer, 0, read); if (inputStream.available() < 1) { outputStream.flush(); } } } while (read >= 0); } finally { if (!outputSocket.isOutputShutdown()) { outputSocket.shutdownOutput(); } } } finally { if (!inputSocket.isInputShutdown()) { inputSocket.shutdownInput(); } } } catch (IOException e) { e.printStackTrace(); // TODO: implement catch } } private String readLine(Socket socket) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); int next; readerLoop: while ((next = socket.getInputStream().read()) != -1) { if (previousWasR && next == '\n') { previousWasR = false; continue; } previousWasR = false; switch (next) { case '\r': previousWasR = true; break readerLoop; case '\n': break readerLoop; default: byteArrayOutputStream.write(next); break; } } return byteArrayOutputStream.toString("ISO-8859-1"); } } } 

用于HTTPS协议的URLConnection的默认java SE7实现使用参数
https.proxyHosthttps.proxyPort

添加到Tomcat:

-Dhttps.proxyHost =“192.168.121.31”-Dhttps.proxyPort =“3128”