【问题标题】:Debian SSL certificates ERROR: cannot verify xxx certificate / javax.net.ssl.SSLHandshakeExceptionDebian SSL 证书错误:无法验证 xxx 证书 / javax.net.ssl.SSLHandshakeException
【发布时间】:2014-07-24 16:49:06
【问题描述】:

我有一个奇怪的问题(这是 100% 服务器配置问题),例如我想从 Dropbox 下载一些东西:

正在解决 dl.dropboxusercontent.com... 23.23.160.146、50.17.227.107、 54.221.248.69, ... 正在连接到 dl.dropboxusercontent.com|23.23.160.146|:443... 已连接。错误: 无法验证 dl.dropboxusercontent.com 的证书,由 “/C=US/ST=CA/O=SonicWALL Inc./CN=SonicWALL 防火墙 DPI-SSL”:
遇到自签名证书。连接到 dl.dropboxusercontent.com 不安全,请使用“--no-check-certificate”。

是的,我知道我可以使用 --non-check-certificate 但是当我想在 Java 应用程序中使用 SSL 连接时,我有这样的事情:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:PKIX 路径构建失败: sun.security.provider.certpath.SunCertPathBuilderException:无法 找到请求目标的有效认证路径

这个应用程序在其他服务器或本地机器上运行良好,你知道这里有什么问题吗?

【问题讨论】:

    标签: java ssl https


    【解决方案1】:

    /C=US/ST=CA/O=SonicWALL Inc./CN=SonicWALL 防火墙 DPI-SSL

    您的流量明显被深度数据包检测防火墙拦截,该防火墙充当 MITM 代理来监控您的流量。

    这通常可以被认为是“合法的”MITM 攻击者。 (无论这是否合法,这可能取决于许多法律和道德方面。)您的本地网络管理员应该能够告诉您一些有关这方面的信息。如果这是公司网络的一部分,则该公司正在监视您的流量,包括您的 HTTPS 连接的内容(因此端到端不再安全)。如果防火墙正常工作,它仍然应该保护从防火墙到服务器的连接(可能很难知道它是否正确检查证书。)

    一般来说,这样的防火墙或代理充当自己的证书颁发机构,有效地根据请求伪造每个证书。

    公司网络上的大多数客户端都会信任它颁发的证书(就像您面临的那样),因为系统管理员还会将 CA 证书作为受信任的证书安装到该网络中的每台计算机中。您可能拥有操作系统受信任的根证书。

    但是,网络管理员很可能没有将此 CA 证书安装到您的 JRE 安装中(默认情况下,它使用自己的一组信任锚)。

    尝试从参考机器导出该 CA 证书(请参阅上面的名称)并将其导入您正在使用的信任库(您的 JRE 的默认信任库:cacerts 或您构建并传递给您的应用程序的新信任库通过javax.net.trustStore 属性)。

    通常,您可以使用这样的东西(假设您已将防火墙的 CA 导出为“firewallca.pem”):

    keytool -import -file firewallca.pem -alias firewallca -keystore truststore.jks
    

    如果truststore.jks 文件不存在,它将被创建。否则,您可以在 JRE 的 lib/security 目录中获取 cacerts 文件的副本。您也可以直接在 cacerts 文件上执行此操作(使用 -keystore /path/to/truststore.jks,前提是您具有写入权限)。

    如果您选择不在默认信任库(即 cacerts 文件)上执行此操作,而是使用像 truststore.jks 这样的本地信任库,则可以在运行应用程序时通过使用此系统属性来使用它:-Djavax.net.trustStore=/path/to/truststore.jks

    有关配置信任库的其他方式,请查看this answer


    解决此问题的另一种方法是告诉 Java 使用 your OS's truststore。我假设您在这里使用的是 Windows。使用这些系统属性应该可以工作:

    -Djavax.net.trustStore=NONE -Djavax.net.trustStoreType=WINDOWS-ROOT
    

    (如果这不起作用,请尝试使用 WINDOWS-MY 而不是 WINDOWS-ROOT。)

    WINDOWS-MY/WINDOWS-ROOT 有点错误,因为它会丢失 Windows 商店中的一些证书:它使用证书“友好名称”(非唯一)作为密钥库别名(唯一),所以具有给定友好名称的证书将隐藏具有相同名称的其他证书。 (不幸的是,这有效地减少了受信任的 CA 证书的数量。)

    由于您所处的环境可能所有流量都通过您的 DPI 防火墙,因此您可能最多只需要使用一个 CA 证书。只要它在 Windows 列表中不与任何其他证书共享其“友好名称”,就可以了。

    【讨论】:

    • “这通常可以被认为是‘合法的’MITM 攻击者”——不存在合法攻击。这就像说你可以怀孕一半。 (1) Dropbox 是否同意被拦截(可能不会)。 (2) 你如何教程序员区分“好”坏人和“坏”坏人(你不能)?
    • @jww 我不反对,但公司检查其所有 SSL 流量是有意义的。这不是 Dropbox 被拦截,而是公司监控其网络。
    【解决方案2】:

    您需要在客户端的 Java 密钥库中添加服务器的 SSL 证书。看看这个 SO 帖子:

    Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Error?

    提示:这是因为您客户端的 JVM 不“信任”服务器的 SSL 证书。所以你需要在你的密钥库中添加证书。

    【讨论】:

    • 是否有可能“信任”每个网络?
    • @user3771297 如果您信任所有证书,这将使证书的整个概念无效:) 但是,您可能想看看这个stackoverflow.com/questions/2893819/… 我建议宁愿使用--no-check-certificate您提到的选项。但是,你确定吗?
    • @user3771297 有一些方法可以禁用证书验证,但在 99.9999999% 的情况下,它们都是一个糟糕的主意。它感觉是一种快速的方法,但它会在以后带来更多麻烦:您要么必须在该代码投入生产之前删除该代码,要么您会忘记并在您的代码中留下一个安全漏洞应用程序(请记住,您在没有解决问题的情况下关闭了“警报”,在发布之前可能不会引起注意)。两者都不是好选择。
    • @user3771297:“有没有可能‘信任’每个网络”。正如帕特和布鲁诺所说,这是一个非常糟糕的主意。但是,如果您不关心证书验证,请不要使用证书。您可以通过使用其中一种加密套件来做到这一点:匿名 Diffie-Hellman (ADH) 或匿名椭圆曲线 Diffie-Hellman (AECDH)。当密码套件是 ADH 或 AECDH 时,服务器不会发送证书。但是,如果您不打算正确使用 PKIX,为什么还要使用 SSL/TLS?
    • 顺便说一句,您需要添加服务器(或 CA)证书的不是 keystore,而是 truststore
    猜你喜欢
    • 2014-09-24
    • 2011-08-19
    • 1970-01-01
    • 2013-10-03
    • 2022-09-25
    • 2018-12-25
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    相关资源
    最近更新 更多