当前位置: 首页 > 知识库问答 >
问题:

Apache HTTPClient SSLPeerUnverifiedException

景成和
2023-03-14

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

我已尝试将证书导入密钥库a la

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

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

有什么想法吗?

共有2个答案

洪和平
2023-03-14

创建自定义上下文,以便记录证书无效的原因。或者只是调试一下。

漆雕欣德
2023-03-14

编辑:我意识到这个答案很久以前就被接受了,而且也被提升了三次,但它(至少部分)是不正确的,所以这里有更多关于这个例外的信息。抱歉给您带来不便。

javax。网ssl。SSLPeerUnverifiedException:对等方未经过身份验证

这通常是远程服务器根本不发送证书时引发的异常。然而,在使用ApacheHTTP客户机时会遇到一种边缘情况,这是因为它在这个版本中的实现方式,以及sun的方式。安全ssl。SSLSocketImpl。getSession()已实现。

使用Apache HTTP客户端时,如果远程证书不受信任,也会引发此异常,这通常会引发“sun.security.validator.ValidatorException:PKIX路径构建失败”。

发生这种情况的原因是,Apache HTTP客户端在执行任何其他操作之前,试图获取SSLSession和对等证书。

作为提醒,有三种方法可以通过SSLSocket启动握手:

  • 调用startHandshake,明确开始握手,或

这里有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路径构建失败”(如预期)。

例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路径构建失败”(如预期)。

例3:

    SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
    SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
            443);
    SSLSession sslSession = sslSocket.getSession();
    sslSession.getPeerCertificates();

然而,这会抛出javax。网ssl。SSLPeerUnverifiedException:对等方未经身份验证

这是ApacheHTTP客户机的AbstractVerifier中实现的逻辑,由其组织使用。阿帕奇。http。康涅狄格州。版本4.2.1中的SSLSocketFactory。根据HTTPCLIENT-1346发布的报告,更高版本会显式调用startHandshake()

这最终似乎来自于sun.security.ssl. SSLSocketImpl.get会话()的实现,它捕获了调用starHandshake(false)(内部方法)时抛出的潜在IOExctives,而不会进一步抛出它。这可能是一个bug,尽管这不应该产生巨大的安全影响,因为无论如何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();

谢天谢地,每当您实际尝试使用该SSLSocket(通过在没有获得对等证书的情况下获取会话,没有漏洞)时,这仍然会抛出“javax.net.ssl.SSLHandshakeException:sun.security.validator.validator exception:PKIX路径构建失败”。

如何解决这个问题

与不受信任的证书的任何其他问题一样,问题在于确保您使用的信任存储包含必要的信任锚(即,颁发您试图验证的链的CA证书,或者在例外情况下可能是实际的服务器证书)。

要解决这个问题,您应该将CA证书(或者可能是服务器证书本身)导入到您的信任存储中。你可以这样做:

  • 在JRE信任库中,通常是cacerts文件(这不一定是最好的,因为这会影响所有使用该JRE的应用程序),
  • 在信任存储的本地副本中(您可以使用-Djavax.net.ssl.trustStore=…选项配置该副本),
  • 通过为该连接创建特定的SSLContext(如本答案所述)。(有些人建议使用不执行任何操作的信任管理器,但这会使您的连接容易受到MITM攻击。)

初步答案

javax。网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。阿帕奇。http。康涅狄格州。SSLSocketFactory并将其用于与Apache Http客户端的连接。

这个工厂将需要创建一个SSLSocket像往常一样,使用sslSocket.setEnabled协议(new String[]{"SSLv3"});在返回该套接字之前,禁用TLS,否则将默认启用。

 类似资料:

相关问答

相关文章

相关阅读