Java https 代理(使用 https.proxyPort 和 https.proxyHost) [英] Java https proxy (using https.proxyPort and https.proxyHost)

查看:60
本文介绍了Java https 代理(使用 https.proxyPort 和 https.proxyHost)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个依赖于设置 http.proxyPorthttp.proxyHost 的 Java 应用程序.有两个进程:一个是正则程序,一个是代理.我有一个在 http.proxyPort(我控制)上运行的简单套接字侦听器.就这么简单

while (true) {尝试 {套接字连接 = server.accept();Handler handler = new Handler(connection);处理程序开始();} 捕捉(异常前){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,但我确实已经尝试了几个月(断断续续,这不是太重要)而没有运气.我已经阅读了很多主题(我会在最后列出一些以便您知道我做了一些事情).

到目前为止我最接近的尝试:服务器

尝试{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("准备就绪");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 连接建立
" +"内容长度:" + "关闭!".getBytes().length+ "
").getBytes("utf-8"));toClient.write("关机!".getBytes("utf-8"));toClient.close();} catch(异常异常){异常.printStackTrace();}

客户

尝试{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(新的 InputStreamReader(yc.getInputStream()));字符串输入行;while ((inputLine = in.readLine()) != null)System.out.println(inputLine);附寄();} 捕捉(异常前){ex.printStackTrace();}

我收到这个错误 javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? 我用谷歌搜索了它,但找到了一些邮件内容.

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

我尝试过的一些网站...

解决方案

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

引用draft-luotonen-web-proxy-隧道-01.txt:

<块引用>

 客户端 ->服务器服务器 ->客户------------------------------ -------------------------------------连接 home.netscape.com:443 HTTP/1.0用户代理:Mozilla/4.0<<<空行 >>>HTTP/1.0 200 连接已建立代理:Netscape-Proxy/1.1<<<空行 >>><<<到两个方向的数据隧道开始>>>

所以基本上你需要确保你足够信任你的客户端,从你的代理防火墙位置连接到给定的主机和端口.因为这种常见的做法是将允许的端口限制为 443,拒绝与本地主机和来自不受信任"方的连接.

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

import java.io.*;导入 java.net.ServerSocket;导入 java.net.Socket;导入 java.util.regex.Matcher;导入 java.util.regex.Pattern;/*** 为 http://stackoverflow.com/q/16351413/1266906 创建.*/公共类服务器扩展线程{公共静态无效主(字符串 [] args){(新服务器()).run();}公共服务器(){super("服务器线程");}@覆盖公共无效运行(){试试 (ServerSocket serverSocket = new ServerSocket(9999)) {插座插座;尝试 {while ((socket = serverSocket.accept()) != null) {(new Handler(socket)).start();}} catch (IOException e) {e.printStackTrace();//TODO: 实现捕获}} catch (IOException e) {e.printStackTrace();//TODO: 实现捕获返回;}}公共静态类处理程序扩展线程{public static final Pattern CONNECT_PATTERN = Pattern.compile("CONNECT (.+):(.+) HTTP/(1\.[01])",Pattern.CASE_INSENSITIVE);私有最终 Socket clientSocket;private boolean previousWasR = false;公共处理程序(套接字客户端套接字){this.clientSocket = clientSocket;}@覆盖公共无效运行(){尝试 {String request = readLine(clientSocket);System.out.println(请求);匹配器 matcher = CONNECT_PATTERN.matcher(request);如果(匹配器.匹配()){字符串头;做 {header = readLine(clientSocket);} while (!"".equals(header));OutputStreamWriter outputStreamWriter = new OutputStreamWriter(clientSocket.getOutputStream(),"ISO-8859-1");最终 Socket forwardSocket;尝试 {forwardSocket = new Socket(matcher.group(1), Integer.parseInt(matcher.group(2)));System.out.println(forwardSocket);} catch (IOException | NumberFormatException e) {e.printStackTrace();//TODO: 实现捕获outputStreamWriter.write("HTTP/" + matcher.group(3) + " 502 Bad Gateway
");outputStreamWriter.write("Proxy-agent: Simple/0.1
");outputStreamWriter.write("
");outputStreamWriter.flush();返回;}尝试 {outputStreamWriter.write("HTTP/" + matcher.group(3) + " 200 连接建立
");outputStreamWriter.write("Proxy-agent: Simple/0.1
");outputStreamWriter.write("
");outputStreamWriter.flush();线程 remoteToClient = 新线程(){@覆盖公共无效运行(){forwardData(forwardSocket,clientSocket);}};remoteToClient.start();尝试 {如果(以前的WasR){int read = clientSocket.getInputStream().read();如果(读!= -1){如果(读!= '
'){forwardSocket.getOutputStream().write(read);}转发数据(clientSocket,forwardSocket);} 别的 {如果 (!forwardSocket.isOutputShutdown()) {forwardSocket.shutdownOutput();}如果 (!clientSocket.isInputShutdown()) {clientSocket.shutdownInput();}}} 别的 {转发数据(clientSocket,forwardSocket);}} 最后 {尝试 {remoteToClient.join();} catch (InterruptedException e) {e.printStackTrace();//TODO: 实现捕获}}} 最后 {forwardSocket.close();}}} catch (IOException e) {e.printStackTrace();//TODO: 实现捕获} 最后 {尝试 {clientSocket.close();} catch (IOException e) {e.printStackTrace();//TODO: 实现捕获}}}私有静态无效forwardData(套接字输入套接字,套接字输出套接字){尝试 {InputStream inputStream = inputSocket.getInputStream();尝试 {OutputStream outputStream = outputSocket.getOutputStream();尝试 {字节[]缓冲区=新字节[4096];读入;做 {读取 = inputStream.read(buffer);如果(读取> 0){outputStream.write(buffer, 0, read);如果 (inputStream.available() <1) {outputStream.flush();}}} while (读>= 0);} 最后 {如果 (!outputSocket.isOutputShutdown()) {outputSocket.shutdownOutput();}}} 最后 {如果 (!inputSocket.isInputShutdown()) {inputSocket.shutdownInput();}}} catch (IOException e) {e.printStackTrace();//TODO: 实现捕获}}私有字符串 readLine(Socket socket) 抛出 IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();下一个;读者循环:while ((next = socket.getInputStream().read()) != -1) {if (previousWasR && next == '
') {以前的WasR = 假;继续;}以前的WasR = 假;切换(下一个){案例
":以前的WasR = true;打破 readerLoop;案例
":打破 readerLoop;默认:byteArrayOutputStream.write(next);休息;}}return byteArrayOutputStream.toString("ISO-8859-1");}}}

I was making a Java application that relies on setting http.proxyPort and http.proxyHost. 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). 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

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? Like instead use 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. 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
" +
            "Content-Length: " + "Shut down!".getBytes().length
                                     + "
").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? 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://..."))

A few of the sites I tried...

解决方案

As auntyellow commented: you don't need to do any SSL-fiddling yourself. Basically https-proxying is about forwarding binary data between two parties.

To cite 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.

This is a "simple" server which is usable as https.proxy in Java if you are not jet convinced:

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
");
                        outputStreamWriter.write("Proxy-agent: Simple/0.1
");
                        outputStreamWriter.write("
");
                        outputStreamWriter.flush();
                        return;
                    }
                    try {
                        outputStreamWriter.write("HTTP/" + matcher.group(3) + " 200 Connection established
");
                        outputStreamWriter.write("Proxy-agent: Simple/0.1
");
                        outputStreamWriter.write("
");
                        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 != '
') {
                                        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 == '
') {
                    previousWasR = false;
                    continue;
                }
                previousWasR = false;
                switch (next) {
                    case '
':
                        previousWasR = true;
                        break readerLoop;
                    case '
':
                        break readerLoop;
                    default:
                        byteArrayOutputStream.write(next);
                        break;
                }
            }
            return byteArrayOutputStream.toString("ISO-8859-1");
        }
    }
}

这篇关于Java https 代理(使用 https.proxyPort 和 https.proxyHost)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆