简体   繁体   English

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

[英]Java https proxy (using https.proxyPort and https.proxyHost)

I was making a Java application that relies on setting http.proxyPort and http.proxyHost . 我正在制作一个依赖于设置http.proxyPorthttp.proxyHost的Java应用程序。 There are two processes: One is the regular program, the other is the proxy. 有两个过程:一个是常规程序,另一个是代理。 I have a simple socket listener running on http.proxyPort (which I control). 我有一个在http.proxyPort运行的简单套接字监听http.proxyPort (我控制)。 It's as simple as 这很简单

while (true) {
    try {
    Socket connection = server.accept();

    Handler handler = new Handler(connection);
    handler.start();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

So whenever "process 1" makes an http request - like 所以每当“进程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()));

It goes through the proxy. 它通过代理。 Now what if the client is using an HTTPS protocol? 现在如果客户端使用HTTPS协议怎么办? Like instead use https://google.ca ? 比如使用https://google.ca There's a property https.proxyPort and https.proxyHost , but I've literally been trying for months (on and off, it's not too important) without luck. 有一个属性https.proxyPorthttps.proxyHost ,但我确实已经尝试了几个月(开启和关闭,它不是太重要)没有运气。 I've read a bunch of threads (I will list some at the end so you know I have done something). 我已经阅读了一堆线程(我会在最后列出一些,所以你知道我已经做了一些事情)。

My closest attempt so far: Server 我迄今为止最接近的尝试:服务器

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();
}

Client 客户

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();
}

And I get this error javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? 我得到这个错误javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? I googled it but came up with some mail stuff instead. 我用谷歌搜索了它,但是想出了一些邮件。

Basically, I need to create a java proxy server, that's set to the client by the https.proxyPort and https.proxyHost flags, and can send data back to the client app, which may not be modified in any way (it's just using URL connection = new URL("https://...") ) 基本上,我需要创建一个java代理服务器,它通过https.proxyPorthttps.proxyHost标志设置到客户端,并且可以将数据发送回客户端应用程序,这可能不会以任何方式进行修改(它只是使用URL connection = new URL("https://...")

A few of the sites I tried... 我试过的几个网站......

As auntyellow commented: you don't need to do any SSL-fiddling yourself. 正如auntyellow评论的那样:你不需要自己做任何SSL摆弄。 Basically https-proxying is about forwarding binary data between two parties. 基本上,https-proxying是关于在两方之间转发二进制数据。

To cite draft-luotonen-web-proxy-tunneling-01.txt : 引用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 >>> 

So basically you need to ensure you trust your client enough to connect from your proxies firewall-position to the given host and port. 所以基本上你需要确保你信任你的客户足以从你的代理防火墙位置连接到给定的主机和端口。 Because of this common practice is to limit allowed port to 443, reject connection to localhost and from "untrusted" parties. 由于这种常见做法是将允许端口限制为443,拒绝与localhost和“不可信”方的连接。

This is a "simple" server which is usable as https.proxy in Java if you are not jet convinced: 这是一个“简单”的服务器,如果你不相信,它可以用作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");
        }
    }
}

Default java SE7 implementation of URLConnection for HTTPS protocol uses parameters 用于HTTPS协议的URLConnection的默认java SE7实现使用参数
https.proxyHost and https.proxyPort https.proxyHosthttps.proxyPort

Add to Tomcat: 添加到Tomcat:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM