使用Apache的HttpClient 4.2.1。 使用从形式复制的代码基于登录示例
http://hc.apache.org/httpcomponents-client-ga/examples.html
我得到一个访问SSL保护的登录表单时,一个异常:
Getting library items from https://appserver.gtportalbase.com/agileBase/AppController.servlet?return=blank
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
Closing http connection
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
证书至于我可以告诉是罚款(见堆栈跟踪前的URL),没有过期 - 浏览器不抱怨。
我试图把该证书导入密钥库我一拉
如何处理与Apache的HttpClient无效的SSL证书?
有没有变化。 我相信你可以创建一个自定义的SSLContext迫使Java来忽略错误,但我宁愿修复的根本原因,因为我不想打开任何安全漏洞。
有任何想法吗?
编辑我意识到这个答案前接受了很长时间,也已经upvoted的3倍,但它是(至少部分)不正确,所以这里是一个比较有关此异常。 不便之处敬请原谅。
javax.net.ssl.SSLPeerUnverifiedException:同行不认证
这通常是在远程服务器没有证书在所有抛出的异常。 然而,有一个边缘的情况下,它是使用Apache HTTP客户端的时候,因为它是在这个版本中实现的方式相遇,因为这样的sun.security. ssl.SSLSocketImpl.getSession()
sun.security. ssl.SSLSocketImpl.getSession()
被实现。
当使用Apache HTTP客户端,此异常也将在远程证书不被信任抛出,这将更多的时候抛出“ sun.security.validator.ValidatorException: PKIX path building failed
”。
出现这种情况的原因是因为Apache HTTP客户端尝试获取SSLSession
和做其他事情之前,对方的证书。
正如一个提醒,也有开始有握手的3种方式SSLSocket
:
- 调用startHandshake其中明确开始握手,或
- 任何试图在此套接字上读取或写入应用程序数据导致隐含的握手,或
- 到的getSession呼叫尝试建立一个会话,如果当前没有有效的会话,并且隐式握手。
这里有3个例子中,所有针对与一个证书的主机是不信任(使用javax.net.ssl.SSLSocketFactory
,而不是Apache之一)。
实施例1:
SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
443);
sslSocket.startHandshake();
这将引发“ javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
”(如预期)。
实施例2:
SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
443);
sslSocket.getInputStream().read();
这也将引发“ javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
”(如预期)。
实施例3:
SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
443);
SSLSession sslSession = sslSocket.getSession();
sslSession.getPeerCertificates();
然而,这将引发javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
。
这是实现的逻辑Apache的HTTP客户端的AbstractVerifier
使用其org.apache.http.conn.ssl.SSLSocketFactory
在4.2.1版本。 后来的版本做出的显式调用startHandshake()
的基础上,报告问题的HttpClient-1346 。
这最终似乎来自实施sun.security. ssl.SSLSocketImpl.getSession()
sun.security. ssl.SSLSocketImpl.getSession()
其捕获电位IOException
在叫时抛出startHandshake(false)
(内部法),不经进一步抛它。 这可能是一个错误,尽管这不应该有一个巨大的安全影响,因为SSLSocket
仍将反正关闭。
实施例4:
SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
443);
SSLSession sslSession = sslSocket.getSession();
// sslSession.getPeerCertificates();
sslSocket.getInputStream().read();
值得庆幸的是,这仍然会抛出“ javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
”,只要你真正尝试使用SSLSocket
有(无漏洞通过获取会话没有得到对等证书)。
如何解决这个问题
就像使用证书的任何其他问题不受信任的,这是确保你正在使用的信任存储包含必要的信任锚(即发行链中的CA证书你想验证,或可能实际服务器的问题对于特殊情况下证书)。
为了解决这个问题,你应该导入CA证书(或可能的服务器证书本身)到您的信任存储区。 你可以这样做:
- 在你的JRE信任库,通常
cacerts
文件(这并不一定是最好的,因为这会影响到使用JRE的所有应用程序), - 在您的信任存储的本地副本(你可以配置使用
-Djavax.net.ssl.trustStore=...
选项) - 通过创建特定
SSLContext
用于该连接(如在描述此答案 )。 (有人建议用它来,什么也不做的信托经理,但这样会使您的连接容易受到中间人攻击。)
最初的回答
javax.net.ssl.SSLPeerUnverifiedException:同行不认证
这无关与信任的证书或您不必创建一个自定义SSLContext
:这是由于服务器不发送任何证书都没有。
此服务器明显未配置为支持TLS正常。 这种失败(您将无法获得远程证书):
openssl s_client -tls1 -showcerts -connect appserver.gtportalbase.com:443
然而,在SSLv3似乎工作:
openssl s_client -ssl3 -showcerts -connect appserver.gtportalbase.com:443
如果您知道是谁在运行该服务器,这将是值得与他们联系,以解决此问题。 服务器应该真正支持至少现在的TLSv1。
同时,为解决这个问题的一种方法是创建自己的org.apache.http.conn.ssl.SSLSocketFactory
,并使用它与Apache HTTP客户端此连接。
这个工厂将需要创建一个SSLSocket
像往常一样,使用sslSocket.setEnabledProtocols(new String[] {"SSLv3"});
返回该套接字之前,要禁用TLS,否则默认情况下启用。
创建自定义背景,因此您可以登录为何证书是无效的。 或者只是调试到它。