信任服务器上所有客户端证书的安全隐患(Java X509TrustManager)

Security implications of trusting all client certificates on a server (Java X509TrustManager)

自定义的“空”X509TrustManager 实现(即信任所有证书的实现,例如这个答案: or "option 2" in this answer: )经常被推荐在此站点和其他站点上。人们(正确地)批评这是不安全和危险的建议。这通常在客户端中用于信任任何服务器证书。

我想知道对于信任任何 client 证书的 server 这种做法是否必然不安全(假设随后单独检查所述证书针对受信任的证书列表)。

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

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

  1. return由 clientSocket.getSession().getPeerCertificates() 编辑的证书是否仍会根据其私钥进行预验证(即,如果有人出示管理员证书,但没有私钥,getPeerCertificates() return 一个空数组)?
  2. 在我的 TrustManager blank/null 中也保留 checkServerTrusted()/getAcceptedIssuers() 方法是否有任何风险?如果这个 TrustManager 只被我的服务器套接字工厂使用,这些方法会被调用吗?
  3. 有没有更好的方法来实现我想要的?

I want to know if this practice is necessarily unsafe for a server trusting any client certificate (assuming said certificate is then checked separately against a list of trusted certs).

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

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

I want to know if this practice is necessarily unsafe for a server trusting any client certificate (assuming said certificate is then checked separately against a list of trusted certs).

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

Is there any risk to also leaving the checkServerTrusted()/getAcceptedIssuers() methods in my TrustManager blank/null? If this TrustManager is only used by my server socket factory, will these methods ever be called?

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