Ich versuche mit der HttpsUrlConnection-Klasse eine Anfrage an einen Server zu senden. Der Server hat Probleme mit Zertifikaten, deshalb habe ich einen TrustManager eingerichtet, der alles vertraut, sowie einen Hostnamen-Verifikator, der gleichermaßen nachsichtig ist. Dieser Manager funktioniert einwandfrei, wenn ich meine Anfrage direkt mache, aber es scheint überhaupt nicht verwendet zu werden, wenn ich die Anfrage über einen Proxy sende.Wie kann ich eine HTTPS-Anfrage über einen Proxy in Java senden?
ich meine Proxy-Einstellungen wie folgt aus:
Properties systemProperties = System.getProperties();
systemProperties.setProperty("http.proxyHost", "proxyserver");
systemProperties.setProperty("http.proxyPort", "8080");
systemProperties.setProperty("https.proxyHost", "proxyserver");
systemProperties.setProperty("https.proxyPort", "8080");
Die Trustmanager für den Standard SSLSocketFactory ist wie folgt aufgebaut:
SSLContext sslContext = SSLContext.getInstance("SSL");
// set up a TrustManager that trusts everything
sslContext.init(null, new TrustManager[]
{
new X509TrustManager()
{
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
{
// everything is trusted
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
{
// everything is trusted
}
}
}, new SecureRandom());
// this doesn't seem to apply to connections through a proxy
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
// setup a hostname verifier that verifies everything
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
{
public boolean verify(String arg0, SSLSession arg1)
{
return true;
}
});
Wenn ich den folgenden Code ausführen, ich mit einem Ende SSLHandshakException ("Remote-Host-Verbindung während Handshake geschlossen"):
Ich gehe davon aus, dass mir eine Einstellung fehlt, bei der es um den Umgang mit SSL geht. Wenn ich keinen Proxy verwende, wird meine checkServerTrusted-Methode aufgerufen. das ist es, was ich tun muss, wenn ich den Proxy durchgehe.
Ich normalerweise nicht mit Java und ich habe nicht viel Erfahrung mit HTTP/Web-Zeug. Ich glaube, ich habe alle notwendigen Details zur Verfügung gestellt, um zu verstehen, was ich versuche zu tun. Wenn das nicht der Fall ist, lass es mich wissen.
Update:
Nach dem Artikel vorgeschlagen von ZZ Coder lesen, habe ich die folgenden Änderungen an den Verbindungscode:
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
connection.setSSLSocketFactory(new SSLTunnelSocketFactory(proxyHost, proxyPort));
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", "0");
connection.connect();
Das Ergebnis (SSLHandshakeException) ist das gleiche. Wenn ich die SLLSocketFactory hier auf die SSLTunnelSocketFactory (die im Artikel erläuterte Klasse) setze, werden die Sachen, die ich mit dem TrustManager und dem SSLContext gemacht habe, außer Kraft gesetzt. Brauche ich das noch?
Ein weiteres Update:
modifizierte ich die SSLTunnelSocketFactory Klasse die SSLSocketFactory zu verwenden, die meine Trustmanager verwendet, der alles vertraut. Es scheint nicht, dass dies einen Unterschied gemacht hat. Dies ist die Methode create von SSLTunnelSocketFactory:
public Socket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException, UnknownHostException
{
Socket tunnel = new Socket(tunnelHost, tunnelPort);
doTunnelHandshake(tunnel, host, port);
SSLSocket result = (SSLSocket)dfactory.createSocket(
tunnel, host, port, autoClose);
result.addHandshakeCompletedListener(
new HandshakeCompletedListener()
{
public void handshakeCompleted(HandshakeCompletedEvent event)
{
System.out.println("Handshake finished!");
System.out.println(
"\t CipherSuite:" + event.getCipherSuite());
System.out.println(
"\t SessionId " + event.getSession());
System.out.println(
"\t PeerHost " + event.getSession().getPeerHost());
}
});
result.startHandshake();
return result;
}
Wenn mein Code ruft connection.connect, diese Methode aufgerufen wird, und der Aufruf an doTunnelHandshake erfolgreich ist. Die nächste Codezeile verwendet meine SSLSocketFactory, um eine SSLSocket zu erstellen. der toString Wert des Ergebnisses nach diesem Aufruf ist:
"1d49247 [SSL_NULL_WITH_NULL_NULL: Socket [adr =/proxyhost, port = proxy, LokalerAnschluss = 24372]]".
Das ist für mich bedeutungslos, aber es könnte der Grund dafür sein, dass die Dinge danach zusammenbrechen.
Wenn result.startHandshake() aufgerufen wird, wird die gleiche createSocket -Methode erneut aufgerufen, entsprechend dem Aufruf-Stack HttpsClient.afterConnect, mit denselben Argumenten, außer Socket s ist null, und wenn es zum Ergebnis kommt .startHandshake() erneut, das Ergebnis ist dieselbe SSLHandshakeException.
Fehle mir immer noch ein wichtiges Stück dieses immer komplizierteren Puzzles?
Dies ist der Stack-Trace:
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:808) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123) at gsauthentication.SSLTunnelSocketFactory.createSocket(SSLTunnelSocketFactory.java:106) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:391) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166) at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133) at gsauthentication.GSAuthentication.main(GSAuthentication.java:52) Caused by: java.io.EOFException: SSL peer shut down incorrectly at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:333) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:789) ... 8 more
Haben Sie schon einmal überprüfen, ob der Proxy geschlossen wurde die Verbindung, dh der Proxy hat eine integrierte Zertifikatsprüfung? – sfussenegger
Die Fehlermeldung lautet "Remote-Host hat Verbindung während Handshake geschlossen". Ist das der Proxy oder der Server, an den ich die Anfrage senden möchte? Ich habe keine Ahnung von der Zertifikatsvalidierung. –
Aus Sicht des Clients würde ich den Proxy auch als remote betrachten. Daher würde ich sicherstellen, dass der Proxy als Fehlerquelle (zumindest) ausgeschlossen wird. Ich habe einige Erfahrung mit Trust Stores und wie schmerzhaft SSL manchmal sein kann. Aber ich habe noch nie eine solche Ausnahme gesehen. Ich habe nie einen Proxy mit SSL benutzt, aber als Erstes würde ich sicherstellen, dass der Proxy Ihrer Verbindung keinen Schaden zufügt. – sfussenegger