【问题标题】:Apache HTTPClient SSLPeerUnverifiedExceptionApache HTTPClient SSLPeerUnverifiedException
【发布时间】:2012-08-19 05:06: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),没有过期 - 浏览器不会抱怨。

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

How to handle invalid SSL certificates with Apache HttpClient?

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

有什么想法吗?

【问题讨论】:

    标签: java ssl apache-httpclient-4.x


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      编辑我意识到这个答案很久以前就被接受了,并且也被投票了 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 客户端在执行任何其他操作之前尝试获取 SSLSession 和对等证书。

      提醒一下,有3 ways of initiating the handshake with an 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 Client's AbstractVerifier 在版本 4.2.1 中使用的 org.apache.http.conn.ssl.SSLSocketFactory 中实现的逻辑。更高版本make an explicit call to startHandshake(),基于issue HTTPCLIENT-1346 中的报告。

      这最终似乎来自sun.security. ssl.SSLSocketImpl.getSession() 的实现,它在调用startHandshake(false)(内部方法)时捕获了潜在的IOExceptions,而没有进一步抛出它。这可能是一个错误,尽管这不会对安全产生重大影响,因为无论如何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.ValidatorException: PKIX path building failed”(在没有获得对等证书的情况下获取会话没有漏洞)。


      如何解决这个问题

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

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

      • 在您的 JRE 信任存储中,通常是 cacerts 文件(这不一定是最好的,因为这会影响使用该 JRE 的所有应用程序),
      • 在您的信任库的本地副本中(您可以使用-Djavax.net.ssl.trustStore=... 选项进行配置),
      • 通过为该连接创建一个特定的SSLContext(如this answer 中所述)。 (有些人建议使用什么都不做的信任管理器,但这会使您的连接容易受到 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,否则默认情况下会启用。

      【讨论】:

      • 嗯,我得到了两者的远程证书。将尝试几个不同的客户
      • 来自 OSX,两者都可以工作,来自 Linux,只有 ssl3。将查看服务器配置。
      • 这可能与密码套件有关。在您的 OSX 客户端上,openssl ciphers DEFAULT 是否具有与您的 Linux 客户端相同的密码套件?有些会在 OSX 列表中但不在 Linux 上?
      • 好的,我通过手动创建像priyanka-tyagi.blogspot.co.uk/2011/08/… 这样的信任管理器来让它工作似乎适用于 TLS 和 SSLv3。不知道如何处理这个答案。这似乎是合理的,可能是一种替代方案,但未经测试。我标记为接受是为了排除疑问,如果有任何理由我不应该这样做,请告诉我
      • @OliverKohll 该信任管理器只是实现了默认行为,即使用 JRE 中的信任存储。如果要使用不同的信任库,只需设置 -Djavax.net.ssl.trustStore=xxx。您不需要代码。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-12
      • 1970-01-01
      • 1970-01-01
      • 2011-10-09
      相关资源
      最近更新 更多