HttpsUrlConnectionクラスを使用してサーバーにリクエストを送信しようとしています。サーバーに証明書の問題があるため、すべてを信頼するTrustManagerと、同様に寛大なホスト名ベリファイアを設定しました。このマネージャーは、直接リクエストを行うと問題なく機能しますが、プロキシを介してリクエストを送信すると、まったく使用されていないようです。
プロキシ設定を次のように設定します。
Properties systemProperties = System.getProperties();
systemProperties.setProperty( "http.proxyHost", "proxyserver" );
systemProperties.setProperty( "http.proxyPort", "8080" );
systemProperties.setProperty( "https.proxyHost", "proxyserver" );
systemProperties.setProperty( "https.proxyPort", "8080" );
デフォルトのSSLSocketFactoryのTrustManagerは、次のように設定されます。
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;
}
} );
次のコードを実行すると、SSLHandshakException(「ハンドシェイク中にリモートホストが接続を閉じました」)が発生します。
URL url = new URL( "https://someurl" );
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
connection.setDoOutput( true );
connection.setRequestMethod( "POST" );
connection.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" );
connection.setRequestProperty( "Content-Length", "0" );
connection.connect();
SSLを処理するときにプロキシを使用することに関係するある種の設定が欠落していると思います。プロキシを使用しない場合、checkServerTrustedメソッドが呼び出されます。これは、私がプロキシを通過するときにも発生する必要があることです。
私は通常Javaを扱っておらず、HTTP/Web関連の経験もあまりありません。私がやろうとしていることを理解するために必要なすべての詳細を提供したと思います。そうでない場合は、私に知らせてください。
アップデート:
ZZ Coderが提案した記事を読んだ後、接続コードに次の変更を加えました。
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();
結果(SSLHandshakeException)は同じです。ここでSLLSocketFactoryをSSLTunnelSocketFactory(記事で説明されているクラス)に設定すると、TrustManagerとSSLContextで行った処理が上書きされます。私はまだそれを必要としませんか?
別の更新:
すべてを信頼するTrustManagerを使用するSSLSocketFactoryを使用するようにSSLTunnelSocketFactoryクラスを変更しました。これが違いを生んだようには見えません。これはSSLTunnelSocketFactoryのcreateSocketメソッドです。
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;
}
私のコードがconnection.connectを呼び出すと、このメソッドが呼び出され、doTunnelHandshakeの呼び出しが成功します。次のコード行では、SSLSocketFactoryを使用してSSLSocketを作成しています。この呼び出し後の結果のtoString値は次のとおりです。
"1d49247 [SSL_NULL_WITH_NULL_NULL:Socket [addr = / proxyHost、port = proxyPort、localport=24372]]"。
これは私には無意味ですが、それがこの後物事が崩壊する理由かもしれません。
result.startHandshake()が呼び出されると、同じcreateSocketメソッドが、呼び出しスタックHttpsClient.afterConnectから、Socket sがnullであることを除いて同じ引数で再度呼び出され、result.startHandshake()が発生します。この場合も、結果は同じSSLHandshakeExceptionになります。
このますます複雑になるパズルの重要な部分がまだ欠けていますか?
これはスタックトレースです。
javax.net.ssl.SSLHandshakeException:ハンドシェイク中にリモートホストが接続を閉じました com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:808)で com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)で com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139)で com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)で gsauthentication.SSLTunnelSocketFactory.createSocket(SSLTunnelSocketFactory.java:106)で sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:391)で sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)で sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)で gsauthentication.GSAuthentication.main(GSAuthentication.java:52)で 原因:java.io.EOFException:SSLピアが正しくシャットダウンしませんでした com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:333)で com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:789)で ...8もっと