Apache HTTPClient SSLPeerUnverifiedException

发布于 2021-01-31 15:28:40

使用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),并且不会过期-浏览器不会抱怨。

我尝试将证书导入到我的密钥库中

如何使用ApacheHttpClient处理无效的SSL证书?

没有变化。我相信您可以创建一个自定义SSLContext来强制Java忽略该错误,但是我宁愿解决根本原因,因为我不想打开任何安全漏洞。

有任何想法吗?

关注者
0
被浏览
62
1 个回答
  • 面试哥
    面试哥 2021-01-31
    为面试而生,有面试问题,就找面试哥。

    编辑 我知道这个答案很久以前就被接受了,并且也被投票了3次,但这是(至少部分是)错误的,所以这里有更多关于此异常的信息。不便之处敬请原谅。

    javax.net.ssl.SSLPeerUnverifiedException:对等方未通过身份验证

    当远程服务器根本不发送证书时, 通常会 抛出此异常。但是,由于在此版本sun.security. ssl.SSLSocketImpl.getSession()中实现的方式以及实现的方式,因此在使用Apache HTTP
    Client时会遇到一些极端情况。

    当使用Apache HTTP Client时,当不信任远程证书时也会抛出该异常,这通常会抛出“
    sun.security.validator.ValidatorException: PKIX path building failed”。

    发生这种情况的原因是因为Apache HTTP Client 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版中使用的逻辑。更高版本基于发出的HTTPCLIENT-1346报告显式调用startHandshake()

    最终,这似乎来自的实现sun.security. ssl.SSLSocketImpl.getSession(),该实现捕获了IOException在调用startHandshake(false)(内部方法)时抛出的潜在s
    ,而没有进一步抛出它。这可能是一个错误,尽管这不会对安全产生重大影响,因为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为该连接创建一个特定对象。(有人建议使用不执行任何操作的信任管理器,但这会使您的连接容易受到MITM攻击。)

    初步答案

    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,否则默认情况下将启用它。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看