阿帕奇了HTTPClient SSLPeerUnverifiedException(Apache H

2019-06-17 21:05发布

使用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来忽略错误,但我宁愿修复的根本原因,因为我不想打开任何安全漏洞。

有任何想法吗?

Answer 1:

编辑我意识到这个答案前接受了很长时间,也已经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,否则默认情况下启用。



Answer 2:

创建自定义背景,因此您可以登录为何证书是无效的。 或者只是调试到它。



文章来源: Apache HTTPClient SSLPeerUnverifiedException