我正在编写一个简单的 Java 代理,它打印客户端的请求,然后将其转发到目标服务器。它必须支持 SSL 连接,因为大多数网页都使用 HTTPS,而不是 ...
我正在编写一个简单的 Java 代理,它打印客户端的请求,然后将其转发到目标服务器。它必须支持 SSL 连接,因为大多数网页都使用 HTTPS 而不是纯 HTTP。所以我使用 SSLSockets 而不是普通的 Sockets。
但是,当我将浏览器配置为通过代理连接并发出请求时,连接被拒绝,并且我收到 SSLException:不支持或无法识别的 SSL 消息
我想我忘记了一些有关 SSL 配置的信息。此外,我正在使用 renatoathaydes / rawhttp 库来轻松管理请求。
这是主要方法,无限循环监听新连接:
public static void main(String... args) {
RequestHandler handler = new RequestHandler();
try {
SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket = (SSLServerSocket) factory.createServerSocket(8080);
while (true) {
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
Runnable action = () -> handler.handleRequest(sslSocket);
Thread thread = new Thread(action);
thread.start();
}
} catch (IOException ex) {
log.error(ex.getMessage(), ex);
}
}
RequestHandler 类负责读取客户端请求、打印到记录器并将其转发到服务器:
@Slf4j
@NoArgsConstructor
public class RequestHandler {
public void handleRequest(SSLSocket clientSocket) {
try {
RawHttpRequest request = readClientRequest(clientSocket);
SSLSocket serverSocket = writeRequestToServer(request);
log.info(request.toString().replace("\\n", ""));
RawHttpRequest serverResponse = readResponseFromServer(serverSocket);
writeResponseToClient(clientSocket, serverResponse);
serverSocket.close();
clientSocket.close();
} catch (IOException ex) {
log.error(ex.getMessage(), ex);
}
}
private RawHttpRequest readClientRequest(SSLSocket clientSocket) throws IOException {
RawHttp http = new RawHttp();
return http.parseRequest(clientSocket.getInputStream());
}
private void writeResponseToClient(SSLSocket clientSocket, RawHttpRequest response) throws IOException {
response.writeTo(clientSocket.getOutputStream());
}
private RawHttpRequest readResponseFromServer(SSLSocket serverSocket) throws IOException {
RawHttp http = new RawHttp();
return http.parseRequest(serverSocket.getInputStream());
}
private SSLSocket writeRequestToServer(RawHttpRequest httpRequest) throws IOException {
String host = httpRequest.getUri().getHost();
int port = httpRequest.getUri().getPort();
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket) factory.createSocket(host, port);
httpRequest.writeTo(sslSocket.getOutputStream());
return (sslSocket);
}
}
我尝试了 SSL 和普通 HTTP 连接,将浏览器配置为通过 localhost 和指定端口 (8080) 进行连接。我将端口更改为 443,这是我所看到的 SSL 端口,但没有效果。
也尝试过不使用 RawHttp 库,但问题是一样的。
那么像这样的事情怎么样:
import javax.net.ssl.*;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
public class SSLProxy {
public static void main(String... args) {
RequestHandler handler = new RequestHandler();
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
}}, new java.security.SecureRandom());
SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket) factory.createServerSocket(8080);
while (true) {
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
Runnable action = () -> handler.handleRequest(sslSocket);
Thread thread = new Thread(action);
thread.start();
}
} catch (IOException | NoSuchAlgorithmException | KeyManagementException ex) {
ex.printStackTrace();
}
}
}
然后
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import rawhttp.core.RawHttp;
import rawhttp.core.RawHttpRequest;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
@Slf4j
@NoArgsConstructor
public class RequestHandler {
public void handleRequest(SSLSocket clientSocket) {
try {
RawHttpRequest request = readClientRequest(clientSocket);
SSLSocket serverSocket = writeRequestToServer(request);
log.info(request.toString().replace("\\n", ""));
RawHttpRequest serverResponse = readResponseFromServer(serverSocket);
writeResponseToClient(clientSocket, serverResponse);
serverSocket.close();
clientSocket.close();
} catch (IOException ex) {
log.error(ex.getMessage(), ex);
}
}
private RawHttpRequest readClientRequest(SSLSocket clientSocket) throws IOException {
RawHttp http = new RawHttp();
return http.parseRequest(clientSocket.getInputStream());
}
private void writeResponseToClient(SSLSocket clientSocket, RawHttpRequest response) throws IOException {
response.writeTo(clientSocket.getOutputStream());
}
private RawHttpRequest readResponseFromServer(SSLSocket serverSocket) throws IOException {
RawHttp http = new RawHttp();
return http.parseRequest(serverSocket.getInputStream());
}
private SSLSocket writeRequestToServer(RawHttpRequest httpRequest) throws IOException {
String host = httpRequest.getUri().getHost();
int port = httpRequest.getUri().getPort() == -1 ? 443 : httpRequest.getUri().getPort();
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket) factory.createSocket(host, port);
httpRequest.writeTo(sslSocket.getOutputStream());
return sslSocket;
}
}
通常情况下,此实现应该信任所有证书。