我正在编写一个系统,该系统必须向具有自签名证书的服务器(一个名为 ARX 的第三方程序,当前在开发期间在本地主机上运行)进行多部分发布。
我试图找到它的证书,但只能找到三个不同的jks文件; server.jks、servertrust.jks 和 serverca.jks。
我尝试使用 System.setProperty("javax.net.ssl.trustStore", "Program Files\\<path>\\jksfile")
每个 jks 文件。然而;当我这样做时,出现以下错误:
证书中的主机名不匹配:< localhost> != <9200416 arx sa cert>。
我在 stackoverflow 上浏览了很多类似的问题,试图了解如何解决这个问题,但我无法解决我的问题。
有什么建议吗?非常感谢所有帮助。
最佳答案
证书本身似乎是可信的,因此您的 javax.net.ssl.trustStore
设置有效,但主机名不匹配。
主机名匹配是根据客户端如何识别它试图访问的主机来完成的。如果它尝试访问 https://localhost/
,则证书必须对 localhost
有效。如果它试图访问 https://something-else.example
,那么证书必须对 something-else.example
有效,即使 localhost
和 something-else.example
是同一台机器。
证书中的标识符应位于主题备用名称扩展中,否则,应位于主题专有名称的通用名称 (CN) 中。
在这里,您的证书似乎只有一个 CN,而这个 CN 是“9200416 arx sa cert
”。
原则上,您可以通过使用开发机器上的 hosts
文件将该名称指向您的本地主机来解决该问题。但是,该名称包含空格,因此它甚至不是有效的主机名。
您有几个选择:
为该应用程序重新生成证书,以便它使用正确的主机名(如果需要,调整您的
hosts
文件)。这可能只是设置时的一个错误。也许有人只是用空格填充了该名称,而没有意识到它会像证书中那样使用(例如,OpenSSL 有时称其为“您的名字”)。将您的应用程序更改为忽略主机名验证是一个糟糕的选择。这是一个糟糕的选择,因为这会使您的代码容易受到 MITM 攻击。当然,这在 localhost 与 localhost 之间几乎无关紧要,但这是保留在代码中的那种代码。因为它会防止错误(否则会是有意的错误)发生,所以很可能会忘记从生产代码中删除它。即使在具有良好开发实践的地方,也很容易错过。这是一个糟糕的选择(只是为了强调这一点)。
一个稍微好一点的变体是有一个自定义主机名 validator 来检查它找到的名称是否是您知道的证书中的名称。
关于java - SSL 握手异常 : hostname in certificate didn't match,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19292473/