使用HttpClient 4.1出现SSL“对等体未经身份验证”错误

23

我正在开发一个简单的应用程序监视器,来轮询我们的API URL,并在无法从响应中获取HTTP 200状态码时发送电子邮件通知我们(这将表明我们的API由于某种原因已停止)。

我正在使用HttpClient 4.1(这很重要,因为它的API与3.x大不相同)。

我们的API是安全的,具有SSL,但是输入:

http://example.com/our-api

进入Web浏览器,将你重定向到

https://example.com/our-api

而不会导致任何错误。

当HttpClient尝试访问此URL(http://example.com/our-api)时,它会失败,并显示一个javax.net.ssl.SSLPeerUnverifiedException异常,其中包含一条消息:“peer not authenticated”。

正如帖子所证明的那样,我看到其他人经常遇到这种情况(该帖子也提供了一些绕过此问题的方法 - 实际上,我今晚要尝试实现这种解决方案)。

这些帖子(以及其他类似的帖子)没有解释为什么会发生这种情况!因此,我不是问“如何解决此问题?”而是问:“为什么会出现此问题?”在我用其中一个建议的解决方案勇往直前之前,我想知道我正在尝试解决的问题是什么 ;-)


1
你能发布完整的堆栈跟踪吗? - Maarten Bodewes
需要注意的是,这个消息可能是由于 HttpClient 中奇怪的编程而引起的。之前可能已经出现了 SSLException 的“握手失败”,这应该是应该抛出的异常。显然,执行继续到了 SSLSession.getPeerCertificate() 调用,这是唯一会抛出标题中异常的 API。 - user207421
4个回答

26
如果服务器的证书是自签名的,那么这是按设计工作的,您必须将服务器的证书导入到密钥库中。
假设服务器证书由知名CA签名,这是因为现代浏览器可用的CA证书集比JDK/JRE附带的有限集合要大得多。
在您提到的帖子中提供的EasySSL解决方案只是隐藏了错误,并且您将无法知道服务器是否具有有效证书。
您必须导入适当的根CA到您的密钥库中以验证证书。不能使用默认的SSL代码绕过此操作的原因是为了防止您编写行为看似安全但实际上不安全的程序。

大多数情况下,SSL服务器将发送证书链,但不包括根证书。因此,大多数时候您不必将整个证书链导入密钥库中。但是,您应该明确信任根证书。 - Maarten Bodewes
@owlstead 是的,通常你只需要导入根证书颁发机构;回答已编辑。 - Jim Garrison
我将证书(base64版本)导入到了lib\security\cacerts下的密钥库中,但Java仍然显示相同的错误。当我将其导入到Windows受信任的证书存储中时,Chrome停止显示错误。但是,当我使用Java keytool导入时,仍然无法连接。 - nurettin
如果服务器仅使用AES_256密码套件,则客户端应该安装JCE无限制权限策略文件 - Hsehdar

7

当对等方无法识别自身时(例如:没有证书,使用的特定密码套件不支持身份验证,或在SSL握手期间未建立对等方身份验证),会抛出此异常。

可能造成此异常的原因(堆栈跟踪在哪里)将向您展示为什么会抛出此异常。最有可能的是,Java附带的默认密钥库不包含(和信任)正在使用的TTP的根证书。

答案是检索根证书(例如从您的浏览器SSL连接中),将其导入到cacerts文件中,并使用Java JDK提供的keytool信任它。否则,您将不得不通过编程方式分配另一个信任存储。


1
keytool -import -v -alias cacerts -keystore cacerts.jks -storepass changeit -file C:\cacerts.cer

0

我不是Java开发人员,但是我正在使用一个Java应用程序来测试RESTful API。为了修复错误,我必须在Web服务器上安装中间证书,以消除错误。我使用的是lighttpd,原始证书已安装在IIS服务器上。希望这可以帮助到您。这些是服务器上缺少的证书。

  • CA.crt
  • UTNAddTrustServer_CA.crt
  • AddTrustExternalCARoot.crt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接