Java https代理(使用https.proxyPort和https.proxyHost) [英] Java https proxy (using https.proxyPort and https.proxyHost)
问题描述
我正在创建一个依赖于设置 http.proxyPort
和 http.proxyHost
的Java应用程序。有两个过程:一个是常规程序,另一个是代理。我有一个简单的套接字监听器在 http.proxyPort
上运行(我控制)。它就像
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();
}
}
所以每当进程1发出http请求时 - 喜欢
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()));
它通过代理。现在如果客户端使用HTTPS协议怎么办?比如使用 https://google.ca
?有一个属性 https.proxyPort
和 https.proxyHost
,但我确实已经尝试了几个月(开启和关闭)没有运气,这不是太重要。我已经阅读了一堆线程(我会在最后列出一些,所以你知道我已经做了一些事情。)
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\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:无法识别的SSL消息,明文连接?
我用谷歌搜索了它,但想出了一些邮件。
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.
基本上,我需要创建一个java代理服务器,通过 https.proxyPort
和 https.proxyHost
标志设置为客户端并且可以将数据发送回客户端应用程序,这可能不会以任何方式进行修改(它只是使用 URL连接=新URL(https:// ...)
)
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...
- 创建接受HTTPS的Java代理服务器
- http://stilius.net/java/java_ssl.php
- 还有其他一些让Java接受所有证书的东西,但我可以找不到任何的联系。我有代码,但是我遇到的错误比我现在做的更多,但如果有帮助我可以加入它(我最初没有,因为这已经是一个很长的问题了)
推荐答案
正如auntyellow评论的那样:你自己不需要做任何SSL摆弄。基本上,https-proxying是关于在两方之间转发二进制数据。
As auntyellow commented: you don't need to do any SSL-fiddling yourself. Basically https-proxying is about forwarding binary data between two parties.
引用 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和不可信方的连接。
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.
这是一个简单服务器,可用作如果您不相信喷气机,请使用Java中的 https.proxy
:
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\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");
}
}
}
这篇关于Java https代理(使用https.proxyPort和https.proxyHost)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!