正如 Boris 在第一条评论中所说,密钥库包含用于身份验证的密钥,而信任库包含受信任的证书,正如其名称所暗示的那样。
首先,证书不必包含私钥。它只是一个带有公钥的身份(可能由受信任方签名,如 CA)。这就是为什么,如果你适当地使用它们,它并不是不安全的。什么是合适的方法?我们开始:
在回答您的问题之前,即不仅服务器而且客户端都经过身份验证的情况,让我们考虑通常的情况:只有服务器经过客户端身份验证。在这种情况下,我们有三方:证书颁发机构 (CA)、服务器 (S) 和客户端 (C)。要使其工作,您应该执行以下操作:
- 为 CA 创建一个密钥对并将其存储在某个
ca.jks 中。
- 从
ca.jks导出证书(只包含公钥,不包含私钥)并导入另一个jks文件,即truststore.jks。
- 为 S 创建另一个密钥对并将其存储在某个
server.jks 中。
- 用 CA 的私钥签署 S 的证书。对于此过程,您需要从
server.jks 生成 CSR(证书签名请求),使用 ca.jks 对 csr 文件进行签名,并生成一些包含已签名证书的 crt(或 pem,无论您想要什么)文件。最后,您必须将此 crt 文件导入回server.jks。使用与以前相同的别名很重要。
- 在 S 中使用
server.jks 作为密钥库,在 C 中使用 truststore.jks 作为信任库。
- 将
ca.jks 保存在安全的地方。它是信任的根源。
这样,C 信任 CA,因为它的证书在他的信任库中。由于 S 有 CA 签署的证书,C 也会信任 S。换句话说,S 是由 C 认证的。
为了实现你想要的,即双方都通过对方的身份验证,你将拥有两个证书颁发机构,即 CA1 和 CA2。 (当然它们可以相同,但为了完整起见,我这样写。)您必须执行上述过程两次:一次使用 CA=CA1,一次使用 CA=CA2。第一个和上面的完全一样。在第二个中,您将创建client.jks,用CA2对其进行签名,并使用CA2的公钥作为S的信任库。(只是交换了C和S的角色。)这样,双方将进行身份验证彼此。
如我所说,可以使用同一个CA,非常方便合理。
我知道这是一个很长的答案,但请确保我省略了大部分细节并尽量使其简单。希望对你有帮助。
编辑: 同样,不要混淆:客户端使用存储在其密钥库中的私钥对自己进行身份验证。证书已经是公开的东西了……
关于你的问题,当然,如果某个小偷窃取了密钥库文件,那么他可以模仿自己成为真正的客户。服务器不知道他在与谁通信,他只验证证书。对于这种情况,可以吊销已颁发的证书。在网上搜索撤销。简单地说,如果您知道客户端的密钥库被盗,您将通过撤销通知服务器这一点,而不是重新生成所有密钥材料。
对此的一个极端情况是,证书是某种公钥与身份的绑定。对于通常情况下的 Web 服务器,他们的证书将他们的公钥与他们的主机名绑定,即主机名是他们的身份。因此如果 abc.com 使用为 xyz.com 颁发的证书,当您尝试连接到 abc.com 时,您的浏览器会报错。在 Java 世界中,这称为主机名验证。证书的common name 字段用于此类身份。 (当你使用 openssl 或 keystore 生成时,它可能会问你一个通用名称,这很重要。)
如果您的客户端实际上是具有静态 IP 或某些有效域名的服务器,您可以使用它。这样,由于小偷会尝试从其他 IP 或域进行连接,服务器将通过主机名验证来检测它。但是,通常客户端没有这种稳定的身份,因此很难使用这种技术,因此小偷可能会模仿真实的客户端。