首页 > 解决方案 > 信任服务器上所有客户端证书的安全隐患 (Java X509TrustManager)

问题描述

自定义“空”X509TrustManager实现(即信任所有证书的实现,例如此答案:https ://stackoverflow.com/a/54358567或此答案中的“选项 2”:https ://stackoverflow.com/a/2893932 ) 经常在本网站和其他网站上推荐。人们(正确地)批评这是不安全和危险的建议。这通常用于客户端信任任何服务器证书。

我想知道这种做法对于信任任何客户端证书的服务器是否一定是不安全的(假设然后根据受信任的证书列表单独检查所述证书)。

背景:我正在尝试创建一个基本的 Gemini 服务器(https://gemini.circumlunar.space/docs/specification.gmi)。提供的大多数页面不需要客户端证书,但如果客户端提供随机证书,我不希望 TLS 握手失败。某些页面(例如管理员的日志查看器)可能需要特定的客户端证书(例如,使用存储在服务器上硬编码文件路径的公钥)。其他页面可能想要信任证书的动态列表(例如来自注册用户的数据库)。

如果我创建一个X509TrustManager信任所有客户端证书的自定义并在我的SSLServerSocketFactory

  1. 仍然返回的证书clientSocket.getSession().getPeerCertificates()是否已针对其私钥进行了预先验证(即,如果有人提供了管理员证书,但没有私钥,将getPeerCertificates()返回一个空数组)?
  2. checkServerTrusted()将我的 TrustManager 中的/getAcceptedIssuers()方法留空/空是否有任何风险?如果此 TrustManager 仅由我的服务器套接字工厂使用,是否会调用这些方法?
  3. 有没有更好的方法来实现我想要的?

标签: javasslx509trustmanagergemini

解决方案


我想知道这种做法对于信任任何客户端证书的服务器是否一定是不安全的(假设然后根据受信任的证书列表单独检查所述证书)。

与首先不请求客户端证书相比,请求但不验证客户端证书不会引入任何安全问题。

使用客户端证书进行身份验证而不对其进行验证显然会增加问题,因为在这种情况下攻击者可能会出示自制的证书。但正如您所写,客户端证书将(希望正确)稍后在 TLS 握手之外进行检查,然后再接受用于身份验证。在这种情况下,不在握手中检查它是完全安全的。

我想知道这种做法对于信任任何客户端证书的服务器是否一定是不安全的(假设然后根据受信任的证书列表单独检查所述证书)。

即使证书验证关闭,仍将验证客户端是否拥有所提供的证书,即它具有匹配的私钥。

将我的 TrustManager 中的 checkServerTrusted()/getAcceptedIssuers() 方法留空/空是否有任何风险?如果此 TrustManager 仅由我的服务器套接字工厂使用,是否会调用这些方法?

checkServerTrusted将被调用来检查服务器证书,即仅在客户端。所以这个功能无关紧要。我不确定getAcceptedIssuers-也许在将接受的 CA 列表发送给客户端时会调用它。不过,此列表是否为空并不重要。


推荐阅读