Java Apache HTTPClient SSLPeerUnverifiedException

Java Apache HTTPClient SSLPeerUnverifiedException,java,ssl,apache-httpclient-4.x,Java,Ssl,Apache Httpclient 4.x,使用ApacheHttpClient 4.2.1。使用从基于表单的登录示例复制的代码 访问受SSL保护的登录表单时出现异常: Getting library items from https://appserver.gtportalbase.com/agileBase/AppController.servlet?return=blank javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated Closing http c

使用ApacheHttpClient 4.2.1。使用从基于表单的登录示例复制的代码

访问受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

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


有什么想法吗?

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

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

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

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

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

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

作为提醒,这里有:

  • 调用明确开始握手的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路径生成失败”(如预期)

例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.net.ssl.SSLPeerUnverifiedException:peer not authenticated

这是版本4.2.1中its使用的在中实现的逻辑。更高版本,基于中的报告

这最终似乎来自的实现,它捕获调用
startHandshake(false)
(内部方法)时抛出的潜在
IOException
s,而不进一步抛出它。这可能是一个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.ValidatorException:PKIX路径构建失败


如何解决这个问题

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

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

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

初步答复

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

这与信任证书无关,或者您必须创建自定义的
SSLContext
:这是因为服务器根本没有发送任何证书

此服务器显然未配置为正确支持TLS。此操作失败(您将无法获得远程证书):

但是,SSLv3似乎可以工作:

如果您知道谁在运行此服务器,请与他们联系以解决此问题。至少在现在,服务器应该真正支持TLSv1

同时,解决此问题的一种方法是创建自己的
org.apache.http.conn.ssl.SSLSocketFactory
,并将其用于与apache http客户端的连接


此工厂需要像往常一样创建一个
SSLSocket
,使用
SSLSocket.setEnabledProtocols(新字符串[]{“SSLv3”})在返回该套接字之前,禁用TLS,否则默认情况下将启用TLS。

Hmm,我将获得一个包含这两个套接字的远程证书。将从OSX的几个不同客户端进行尝试,这两个客户端都可以工作,仅从Linux,ssl3。将查看服务器配置。这可能与密码套件有关。在OSX客户端上,
openssl密码默认值
是否与Linux客户端上的密码套件相同?有些可能在OSX列表中,但在Linux上不存在?好的,我通过手动创建一个信任管理器(如
openssl s_client -tls1 -showcerts -connect appserver.gtportalbase.com:443
openssl s_client -ssl3 -showcerts -connect appserver.gtportalbase.com:443