我将尝试使用HttpsUrlConnection类向服务器发送请求。由于服务器存在证书问题,因此我设置了一个信任所有内容的TrustManager,以及一个同样宽松的主机名验证器。当我直接发出请求时,这个管理器运行得很好,但是当我通过代理发送请求时,它似乎完全没有被使用。
我像这样设置了代理设置:
默认SSLSocketFactory的TrustManager设置如下所示:
如果我运行以下代码,最终会得到一个SSLHandshakeException(“握手期间远程主机关闭了连接”):
我猜测我缺少一些与使用代理处理SSL有关的设置。如果我不使用代理,我的checkServerTrusted方法会被调用;当我通过代理时,这也是我需要发生的事情。
我通常不处理Java,也没有太多HTTP/网络方面的经验。我相信我已经提供了所有必要的细节,以便理解我试图做什么。如果不是这种情况,请让我知道。
更新:
在阅读ZZ Coder建议的文章后,我对连接代码进行了以下更改:
结果(SSLHandshakeException)是相同的。当我在这里将SLLSocketFactory设置为SSLTunnelSocketFactory(文章中解释的类),我对TrustManager和SSLContext所做的操作被覆盖了。我还需要那个吗?
另一个更新:
我修改了SSLTunnelSocketFactory类,使用了使用信任所有内容的TrustManager的SSLSocketFactory。看起来这没有任何区别。这是SSLTunnelSocketFactory的createSocket方法:
当我的代码调用connection.connect时,会调用此方法,并且调用doTunnelHandshake成功。代码的下一行使用我的SSLSocketFactory创建一个SSLSocket;在此调用后,result的toString值为:“1d49247[SSL_NULL_WITH_NULL_NULL: Socket[addr=/proxyHost,port=proxyPort,localport=24372]]”。这对我来说毫无意义,但这可能是事情在此之后出现问题的原因。
调用result.startHandshake()时,从同一createSocket方法中再次调用,根据调用堆栈,是HttpsClient.afterConnect,参数相同,除了Socket s为空,当再次到达result.startHandshake()时,结果仍然是相同的SSLHandshakeException。
我是否仍然缺少这个日益复杂的难题的重要部分?
这是堆栈跟踪:
javax.net.ssl.SSLHandshakeException:握手期间远程主机关闭连接 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) 原因是:java.io.EOFException:SSL对等方关闭连接不正确 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
我像这样设置了代理设置:
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;
}
} );
如果我运行以下代码,最终会得到一个SSLHandshakeException(“握手期间远程主机关闭了连接”):
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/网络方面的经验。我相信我已经提供了所有必要的细节,以便理解我试图做什么。如果不是这种情况,请让我知道。
更新:
在阅读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所做的操作被覆盖了。我还需要那个吗?
另一个更新:
我修改了SSLTunnelSocketFactory类,使用了使用信任所有内容的TrustManager的SSLSocketFactory。看起来这没有任何区别。这是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;在此调用后,result的toString值为:“1d49247[SSL_NULL_WITH_NULL_NULL: Socket[addr=/proxyHost,port=proxyPort,localport=24372]]”。这对我来说毫无意义,但这可能是事情在此之后出现问题的原因。
调用result.startHandshake()时,从同一createSocket方法中再次调用,根据调用堆栈,是HttpsClient.afterConnect,参数相同,除了Socket s为空,当再次到达result.startHandshake()时,结果仍然是相同的SSLHandshakeException。
我是否仍然缺少这个日益复杂的难题的重要部分?
这是堆栈跟踪:
javax.net.ssl.SSLHandshakeException:握手期间远程主机关闭连接 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) 原因是:java.io.EOFException:SSL对等方关闭连接不正确 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