我有一个客户端-服务器游戏,客户端连接到服务器并在游戏期间保持连接(大约 5-60 分钟)。
我希望新客户能够安全地注册,并允许现有客户进行身份验证,而不必担心登录凭据被暴露。
问题是,出于性能原因,最好在游戏会话中坚持使用简单且廉价的加密,如 RC4,但对称密钥并不容易确保注册过程的安全。
由于无论如何我都想保留一个单独的登录服务器,所以我的想法是这样的:
- 客户端使用凭据(或注册信息)向登录服务器发送 HTTPS 请求
- 登录服务器收集用户信息,并生成临时 RC4 会话加密密钥
- 用户信息 + RC4 会话 + 时间戳 + 摘要(我可以依靠两个服务器在时间上同步)与秘密对称密钥,在游戏服务器和登录服务器之间共享。
- 打包后的数据 + RC4 会话加密密钥 + 游戏服务器的 ip 地址作为对 HTTPS 请求的回复发送给客户端。
- 客户端打开与游戏服务器的连接,发送初始未加密的 hello 消息,并将加密的用户信息作为有效负载。
- 游戏服务器解包(3)中打包的数据。它现在知道用户和它应该使用的 RC4 加密密钥。
- 如果时间戳指示登录凭据已过期,则会向客户端返回错误(然后客户端将检索新信息)。如果无法使用摘要验证解密的用户数据,则会返回不同的错误。
- 如果一切正常,服务器会发送一个未加密的 LOGIN_OK,然后开始 RC4 加密通信。
可能的安全问题:
游戏服务器 100% 信任它解密的用户信息。这使得服务器完全解耦,这很好,但如果密钥被泄露,用户可以完全伪造他们的用户信息。这可以通过轮换这些键得到一定程度的缓解,这样每天或每个月都有一个新的键。游戏和登录服务器都可以从管理其密钥的第三个服务器获取此信息。这可能是矫枉过正,因为:a)如果在服务器上暴露源代码的闯入情况下,可以使用新密钥重新启动它们 b)足够好的密钥+加密应该使蛮力攻击变得困难(关于算法的建议?)
RC4 不是最安全的算法,但我确保丢弃前 512 个字节左右,并且每个密钥仅在有限的时间内有效,例如 24 小时。
从我所见,似乎不受中间人的影响:SSL 保护 RC4 会话密钥,在 (5) 中,发送到游戏服务器的 RC4 会话密钥也被加密。唯一可能的是 DoS 并导致用户再次请求密钥。如果(2)中的数据被缓存到过期,这不应该创建一个新的数据包。
(3)中的加密可以通过向密钥添加随机位来改进。这些随机位与加密数据包一起发送,并在(5)中呈现给游戏服务器。在 (6) 中,游戏服务器将这些随机位添加到他的密钥中,并使用结果来解密数据。这样,攻击者就无法看到打包数据何时发生变化。
我在这里忽略了任何漏洞吗?
创建的有效负载摘要:
- 客户端登录凭据(受 SSL 保护),发送到登录服务器
- 用户信息 + 时间戳 + 临时游戏服务器会话密钥 + 由登录服务器使用与游戏服务器共享的密钥加密的摘要,提供给客户端 - 无需修改它 - 将其传递给游戏服务器。应该是耐回火的,因为:a)客户端不知道密钥 b)具有时间戳以避免重新发送相同的数据 c)用于验证内容是否正确加密的摘要
- 登录服务器向客户端发送的临时游戏服务器会话密钥以及加密的有效负载。受 SSL 保护。
- 客户端游戏服务器登录包,由登录服务器接收到的加密包组成。
加密密钥摘要:
- 临时游戏服务器会话密钥:由登录服务器随机生成,用于加密游戏服务器<->客户端通信。由登录服务器生成,提供给客户端和游戏服务器。
- 秘密用户信息加密密钥。在游戏服务器和登录服务器之间共享,用于将用户信息传递给游戏服务器,客户端作为信使。客户端不拥有此密钥。