我正在尝试使用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所做的工作将被覆盖。我还不需要吗?
另一个更新:
我将SSLTunnelSocketFactory类修改为使用SSLSocketFactory,该SSLSocketFactory使用可信任所有内容的TrustManager。看来这没有任何区别。这是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:套接字[addr = / proxyHost,port =
proxyPort,localport = 24372]]”
。
这对我来说毫无意义,但这可能是事后崩溃的原因。
调用result.startHandshake()时,根据调用堆栈HttpsClient.afterConnect,使用相同的参数再次调用相同的createSocket方法,不同的是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个
HTTPS代理没有意义,因为出于安全原因,您无法在代理处终止HTTP连接。使用您的信任策略,如果代理服务器具有HTTPS端口,它可能会起作用。您的错误是由使用HTTPS连接到HTTP代理端口引起的。
您可以使用proxy
CONNECT命令使用SSL隧道(很多人称为该代理)通过代理进行连接。但是,Java不支持较新版本的代理隧道。在这种情况下,您需要自己处理隧道。您可以在此处找到示例代码,
http://www.javaworld.com/javaworld/javatips/jw-
javatip111.html
编辑:如果您想击败JSSE中的所有安全措施,您仍然需要自己的TrustManager。像这样
public SSLTunnelSocketFactory(String proxyhost, String proxyport){
tunnelHost = proxyhost;
tunnelPort = Integer.parseInt(proxyport);
dfactory = (SSLSocketFactory)sslContext.getSocketFactory();
}
...
connection.setSSLSocketFactory( new SSLTunnelSocketFactory( proxyHost, proxyPort ) );
connection.setDefaultHostnameVerifier( new HostnameVerifier()
{
public boolean verify( String arg0, SSLSession arg1 )
{
return true;
}
} );
编辑2:我刚刚尝试了几年前使用SSLTunnelSocketFactory编写的程序,它也不起作用。显然,Sun在Java
5的某个时候引入了一个新的错误。请参阅此错误报告,
http://bugs.sun.com/view_bug.do?bug_id=6614957
好消息是SSL隧道错误已修复,因此您可以使用默认工厂。我只是尝试使用代理,并且一切正常。看我的代码,
public class SSLContextTest {
public static void main(String[] args) {
System.setProperty("https.proxyHost", "proxy.xxx.com");
System.setProperty("https.proxyPort", "8888");
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
// set up a TrustManager that trusts everything
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
System.out.println("getAcceptedIssuers =============");
return null;
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
System.out.println("checkClientTrusted =============");
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
System.out.println("checkServerTrusted =============");
}
} }, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(
sslContext.getSocketFactory());
HttpsURLConnection
.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
System.out.println("hostnameVerifier =============");
return true;
}
});
URL url = new URL("https://www.verisign.net");
URLConnection conn = url.openConnection();
BufferedReader reader =
new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这是我运行程序时得到的,
checkServerTrusted =============
hostnameVerifier =============
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
......
如您所见,SSLContext和hostnameVerifier都被调用。仅当主机名与证书不匹配时,才涉及HostnameVerifier。我使用“
www.verisign.net”来触发此操作。
问题内容: 我正在学习Java套接字。我正在尝试向Facebook发送HTTPS GET请求,如下所示: 然后,我尝试侦听来自服务器的传入数据,如下所示: 但是我没有从服务器获得任何返回数据。为什么? 问题答案: 两个答案。 您正在尝试与HTTPS服务器通信。这要求您建立一个SSL / TLS通道。这在纯套接字上确实很难>>您必须实现连接协商,密钥链的客户端验证,会话加密/解密等。 一个更合理的方
问题内容: 我想从Java代码登录到应用程序。这是我的代码… 但我无法登录,它只返回登录页面。 如果有人可以,请帮助我了解我在做什么错。 问题答案: 错误 :-( www-form 中间有多余的空格) 正确
需要通过代理执行REST请求。有几个HTTP代理服务器可用,受基本身份验证的保护。使用Java16。 访问HTTP资源时完全工作的请求示例:
问题内容: 似乎urllib2默认发送HTTP / 1.1请求? 问题答案: urllib2在后台使用httplib进行连接。您可以将其更改为http 1.0,如下所示。我已包含我的apache服务器访问日志,以显示http连接如何更改为1.0 码 访问日志
问题内容: 我是Android的新手,所以关于android的知识还不是很多,好的,请讲到重点,我需要通过用户名和密码进行 登录 ,因为我必须通过JSON进行http requset并返回响应也将以JSON格式提供。所以任何人都可以帮助我。谢谢。 问题答案: 试试这个代码
我的一个EC2实例上有一个graphql服务器正在运行。我也有AWS appsync运行,但目前它只与几个Lambda集成。 我想将我的Appsync连接到graphql服务器,这样Appsync将作为特定查询/变化的代理。 因此,从客户端来看,它将如下所示: 客户端将一个查询发送到APPESNC,让我们假设它看起来像这样: Appsync已经定义了一个查询,它被配置为在graphql服务器上代理