我正在使用 apache2 (2.2.3) 为一个站点提供服务,我希望客户端使用证书进行身份验证。由于我只需要验证出示特定证书的用户是否与过去出示该证书的用户相同,因此签署该证书的 CA 无关紧要。不过,似乎使用SSLVerifyClient require
require SSLCACertificateFile ...
(或SSLCACertificatePath ...
),apache 将只接受该文件/路径中的 CA 签名的证书。有没有办法让 apache 接受任何客户端证书,而不管颁发/签名的 CA 是谁?(即验证客户端是否具有与所提供公钥相对应的私钥,但不必费心验证颁发/签名的 CA)
答案1
正如您所发现的,您可以使用 在 Apache Httpd 中的 SSL/TLS 握手级别禁用证书验证SSLVerifyCLient optional_no_ca
。
您要面对的第二个问题是让客户端发送证书。由于您的证书不打算包含在 PKI 中,因此它们可能是自签名的并且有多个颁发者。
当请求客户端证书时,服务器会发送CertificateRequest
TLS 消息在握手期间发送给客户端。此消息包含以下certificate_authorities
列表:
可接受证书颁发机构的专有名称列表。这些专有名称可能指定根 CA 或下属 CA 所需的专有名称;因此,此消息可用于描述已知根和所需的授权空间。如果 certificate_authorities 列表为空,则客户端可以发送任何适当 ClientCertificateType 的证书,除非有相反的外部安排。
浏览器使用它来选择发送哪个客户端证书(如果有)。
(请注意,有关空列表的部分仅存在于 TLS 1.1 及更高版本的规范中。SSL 3.0 和 TLS 1.0 对此保持沉默,并且在实践中,它也能起作用。)
对此您有两个选择。
如果您期望的客户端证书是自签名的,则它们都将具有不同的颁发者。由于您不知道会发生什么,因此服务器将需要发送一个空列表。为此,请使用
SSLCADNRequestFile
指示并将其指向仅包含空行的文件(如果我没记错的话,它不适用于完全空的文件)。第二个(不太干净)选项。就是就您期望的所有客户端证书共同的颁发者 DN 达成一致,无论它们是否确实由该 CA 证书颁发(或者该 CA 是否存在)。这样做会大大(更多)破坏 PKI 模型。
如果您同意像
CN=Dummy CA
(例如) 这样的颁发者 DN。任何人都可以使用CN=Dummy CA
主题 DN (和颁发者 DN) 构建自签名证书,可能使用不同的密钥。尽管该SSLCADNRequestFile
指令期望使用证书进行配置以构建列表,但这些证书根本不用于验证客户端证书,这只是一种复杂(但在其他指令的上下文中很自然)的配置列表的方式certificate_authorities
。如果您作为服务将具有这些名称的自签名证书放入中SSLCADNRequestFile
,这将使TLS 消息在列表中CertificateRequest
使用(这些只是名称,而不是此阶段的证书)。然后,客户端将能够使用颁发者 DN 获取自己的证书,无论其签名是否可以由该证书(相同密钥)验证,因为这些步骤中不涉及签名验证。CN=Dummy CA
certificate_authorities
CN=Dummy CA
话虽如此,请记住,使用SSLVerifyCLient optional_no_ca
,不会进行真正的证书验证(我想您可以检查变量,SSL_CLIENT_VERIFY
如果您的手动验证只是您已配置的 PKI 的后备解决方案)。您在该阶段所知道的只是客户端拥有它所出示的公钥证书的私钥(由 TLS 消息保证CertificateVerify
):如果您希望进行某种形式的身份验证,则需要执行某种形式的验证。(您不能信任证书的任何内容,即其公钥与其包含的名称/属性之间的任何绑定。)
这对于文件来说不太适用,但您可以对应用程序执行此操作(例如 PHP/CGI/... 甚至 Java,如果您将证书传递给代理的 Java 服务器)。一种基本方法是拥有一个预先知道的公钥列表,或者您可以查看以下想法FOAF+SSL/WebID。
答案2
使用SSLVerifyCLient optional_no_ca
(而不是require
) 会导致 apache 不检查颁发 CA(因此不需要 CA 证书文件或路径)。它允许客户端/用户不提交证书,因此必须单独检查是否使用了证书。
(显然,我只是没有彻底阅读mod_ssl
文档。)