用于身份验证的 Apache 客户端证书

Apache Client Certificates for Authentication

我想通过 API 公开一项服务,并使用 PHP/MySQL 进行两个身份验证因素。一个因素是简单的用户名和密码。对于另一个因素,我正在尝试使用双向 TLS,其中客户端证书与用户名匹配。我打算使用我在装有 Apache 的 CentOS 机器上设置的 CA 的自签名证书,并通过安全通道向客户颁发客户端证书以及私钥。

我找到了一些关于如何使用 SSL 证书设置用户身份验证的不错的文章。目前我发现的最好的如下。

https://cweiske.de/tagebuch/ssl-client-certificates.htm

但是,这篇文章和其他文章在向我解释某些事情方面似乎存在漏洞。我设想的工作方式是,当客户端发出 POST 请求时,连同用户名和密码,还包括一个带有由发给用户的私钥签名的数字签名的证书。然后可以用 public 密钥解密此签名,以确认私钥的所有者发送了消息。但是,这些文章实际上并没有证实这就是正在发生的事情。

相反,他们说 Apache 确认证书是由 CA 证书签署的。他们还解释了如何使用 PHP 访问证书中的字段,例如 SSL_CLIENT_S_DN_Email 和 SSL_CLIENT_M_SERIAL,并使用它们来确认证书属于消息的发送者。但是,我不清楚他们不只是使用 public 证书中的信息。因此,任何可以访问 public 证书的人都可以将其用作验证服务的身份验证因素之一。如果是这样,这意味着它并不是真正的身份验证因素。

我是否错误地认为我希望是这种情况 - 消息中包含的证书确实包含由发给用户的私钥签名的签名,并且 Apache 使用 public 解密签名密钥而不只是确认证书是由 CA 颁发的?

有两点。

在这种情况下(通过证书进行客户端身份验证),服务器要么维护它信任的证书列表,要么维护签署这些证书的 CA。服务器将检查出示的证书属于这两种情况之一。

至于出示的证书,不是任何人都可以出示任何证书,因为TLS交换会要求客户端对相关的私钥做一些事情,因此服务器将能够验证客户端是否确实有相关的私钥public 证书的密钥。

这在 https://en.wikipedia.org/wiki/Transport_Layer_Security#Client-authenticated_TLS_handshake 中有很好的解释,我在这里总结一下:

  1. 与我们的讨论无关的其他步骤
  2. 客户端用证书消息响应,其中包含客户端的证书。
  3. ClientKeyExchange 步骤,我们可以在讨论中跳过
  4. 客户端发送 CertificateVerify 消息,该消息是使用客户端证书的私钥对之前的握手消息进行的签名。可以使用客户端证书的 public 密钥来验证此签名。这让服务器知道客户端可以访问证书的私钥,因此拥有证书。 所以在这里你看到客户端需要用它的私钥做一些事情,服务器将能够验证一下。

当然,只有当您过滤最终客户端证书时,这一切才有效:如果您允许其中任何一个,任何人都可以使用任何身份创建一个有效的证书。

配置 Apache 以允许相互身份验证非常简单,http://httpd.apache.org 上的文档也非常清楚。基本上您需要两个证书:服务器一个安装在 Apache 服务器上,然后是客户端一个,安装在您的 Firefox 浏览器或客户端应用程序或其他设备上。客户端证书必须由 Apache 服务器知道的 CA 之一颁发才能成功进行身份验证。

本项目https://github.com/amusarra/docker-apache-ssl-tls-mutual-authentication实现了Apache SSL/TLS相互认证的完整配置