共享或不共享服务器的公钥?

信息安全 加密 公钥基础设施 密钥交换
2021-08-28 16:27:53

为了加密从我们的(自定义)客户端到我们的(自定义)服务器的通信,我们当前的方案有点像这样:

  1. 客户端使用捆绑的公钥 A 加密一些随机密钥材料。
  2. 大厅服务器用私钥解密,使用加密的密钥材料建立一个对称加密的加密通道。
  3. 客户端通过加密通道从大厅服务器获取另一个用于登录游戏服务器 1 的公钥 B1。(游戏服务器 2 会有公钥 B2 等,每一个都是在服务器重启时生成的)
  4. 客户端连接到游戏服务器并遵循与 1-2 相同的方案来保护通信。

撇开密钥材料是如何生成和使用的不谈,安全性是否有任何变化,我们将其更改为:

  1. 客户端使用捆绑的公钥 A 加密密钥材料
  2. 大厅服务器使用私钥解密,使用加密的密钥材料建立一个对称加密的加密通道。
  3. 客户端连接到游戏服务器并遵循与 1-2 相同的方案以保护与大厅使用的相同公钥“A”的通信(因此大厅和游戏服务器都使用相同的私钥)

换句话说,我们是否通过仅使用捆绑的公钥登录大厅来获得任何增强的安全性?

最后一种选择是使用单独的登录服务器:

  1. 我们创建一个登录服务器,客户端以1-2的方式连接到该服务器
  2. 然后客户端被授予一个新的对称密钥 C 和一个识别号 D
  3. 客户端连接到大厅服务器,以纯文本形式显示数字 D。
  4. 大厅和客户现在使用密钥继续通信(假设 C 在共享数据库或类似数据库中) C
  5. 客户端连接游戏服务器,再次按照3-4建立加密通道。

这些方案中的任何一个是否明显比另一个差或好?我看不出有什么大的不同。

1个回答

大厅和游戏服务器使用相同私钥的一个潜在显着优势是,即使一个或多个游戏服务器密钥被泄露,大厅服务器密钥(其公共部分与客户端捆绑在一起,使很难改变)仍然是安全的。

据推测,游戏服务器比专用大厅服务器呈现出更大(且变化更频繁)的攻击面,因此设计您的系统以能够从对游戏服务器的攻击中恢复是有意义的,同时将大厅服务器作为尽可能难以妥协。

您的第三种选择也有这个优势,因为只有登录服务器需要知道捆绑密钥的私有部分。实际上,根据“大厅”服务器除了身份验证之外的其他功能,将关键身份验证功能分离到专用服务器上可能是一个好主意。

此外,您的第三种选择保证客户端将无法绕过大厅/登录服务器,即使他们以某种方式设法获取了游戏服务器公钥的副本(例如,从另一个受感染的客户端)。(如果客户端以某种方式获取了另一个客户端的对称密钥,客户端仍然可以绕过登录服务器,但由于这些密钥与客户端 ID 相关联,因此您的服务器应该能够检测到它。)根据您的用例,这可能是也可能不是一个优势,但至少它不应该受到伤害。


顺便说一句,我觉得我真的应该修改这个旧答案,注意有一个比上述任何一个更安全(和实用)的选项:

  • 不要在客户端中捆绑任何游戏或大厅服务器公钥。相反,捆绑“根”数字签名密钥的公共部分,同时将私有部分保存在安全的地方(即不在任何可公开访问的服务器上)。

  • 使用私钥对游戏和大厅服务器的公钥进行签名。

  • 当客户端连接到服务器时,服务器首先(通过不安全的通道)提供包含其签名公钥的“证书”。客户端首先使用其捆绑的公共根密钥验证签名,然后使用经过验证的公共密钥建立到服务器的安全通道。

您还需要一些撤销受损服务器密钥的机制。最简单的方法是在签名之前将过期时间戳附加到公共服务器密钥,并让客户端拒绝使用过期密钥。当然,这意味着您必须在服务器密钥过期之前定期更改(或至少重新签名)服务器密钥,这是您想要自动化的事情。

您还可以在您的协议中包含一个选项,例如 auth/lobby 服务器向客户端发送已撤销的服务器密钥列表,即使它们看起来有效,客户端也不应该信任这些密钥。这至少允许快速撤销游戏服务器密钥,而不必等待它们过期。这可能很有用,例如,如果某些游戏服务器由无法轻松接收自动密钥更新的第三方运行,从而使其密钥使用非常短的到期时间很不方便。

当然,另一种选择可能是给这些第三方游戏服务器运营商他们自己的“分支”签名密钥,该密钥本身由根密钥签名,以便他们可以生成和签署他们自己的服务器密钥。当然,客户端随后需要能够跟踪此类签名密钥链,一直到捆绑的根密钥。并且分支密钥需要携带一些(签名的)元数据,指示它们对哪些服务器有效,以便第三方不能例如仅生成和签名他们自己的大厅/身份验证服务器密钥。

不过,好消息是您实际上不必自己实现任何这些功能,因为它们都是TLS(和DTLS )中使用的公钥基础结构模型的一部分,例如您的网络协议浏览器用于安全连接到 Stack Exchange(以及任何其他 HTTPS 网站)。虽然 TLS 是一个非常复杂的协议(由于历史积累的特性),您真的不想自己实现,但有很多TLS 库可供您使用。如今,您的语言运行时很可能甚至捆绑了一个。(如果它可以从URL 获取数据,它会这样做,或者使用与您的操作系统捆绑的一个。)https://

当然,您仍然需要学习如何配置您的 TLS 库以满足您的需求(例如,仅信任您自己的根证书并禁用您不想要的任何旧功能)以及如何生成和签署 TLS 密钥,这本身可能是一项不平凡的任务。但这肯定比自己从头开始实施安全通信协议要容易得多。