【问题标题】:Security: How vulnerable is this authentication/encryption scheme?安全性:这种身份验证/加密方案有多脆弱?
【发布时间】:2011-02-16 10:16:54
【问题描述】:

我有一个客户端-服务器游戏,客户端连接到服务器并在游戏期间保持连接(大约 5-60 分钟)。

我希望新客户能够安全注册,并允许现有客户进行身份验证,而不必担心登录凭据被泄露。

问题是,出于性能原因,最好在游戏会话中坚持使用 RC4 等简单且廉价的加密,但对称密钥并不容易确保注册过程的安全。

由于无论如何我都想保留一个单独的登录服务器,所以我的想法是这样的:

  1. 客户端使用凭据(或注册信息)向登录服务器发送 HTTPS 请求
  2. 登录服务器收集用户信息,生成临时RC4会话加密密钥
  3. 用户信息 + RC4 会话 + 时间戳 + 摘要(我可以依靠两个服务器在时间上同步)与秘密对称密钥,在游戏服务器和登录服务器之间共享。
  4. 打包后的数据 + RC4 会话加密密钥 + 游戏服务器的 IP 地址作为对 HTTPS 请求的回复发送给客户端。
  5. 客户端打开与游戏服务器的连接,发送初始未加密的 hello 消息,并将加密的用户信息作为有效负载。
  6. 游戏服务器解包(3)中打包的数据。它现在知道用户和它应该使用的 RC4 加密密钥。
  7. 如果时间戳表明登录凭据已过期,则会向客户端(然后检索新信息)返回错误。如果无法使用摘要验证解密的用户数据,则会返回不同的错误。
  8. 如果一切正常,服务器会发送一个未加密的 LOGIN_OK,然后开始 RC4 加密通信。

可能的安全问题:

  • 游戏服务器 100% 信任它解密的用户信息。这使得服务器完全解耦,这很好,但如果密钥被泄露,用户可以完全伪造他们的用户信息。这可以通过轮换这些键得到一定程度的缓解,这样每天或每个月都有一个新的键。游戏和登录服务器都可以从管理其密钥的第三个服务器获取此信息。这可能是矫枉过正,因为:a)如果在服务器上暴露源代码的闯入情况下,可以使用新密钥重新启动它们 b)足够好的密钥+加密应该使蛮力攻击变得困难(关于算法的建议?)

  • RC4 不是最安全的算法,但我确保丢弃前 512 个字节左右,并且每个密钥仅在有限的时间内有效,例如24 小时。

  • 据我所见,似乎不容易受到中间人的影响:SSL 保护 RC4 会话密钥,在 (5) 中,发送到游戏服务器的 RC4 会话密钥也被加密。唯一可能的是 DoS 并导致用户再次请求密钥。如果(2)中的数据被缓存到过期,这不应该创建一个新的数据包。

  • 可以通过向密钥添加随机位来改进 (3) 中的加密。这些随机位与加密数据包一起发送,并在(5)中呈现给游戏服务器。在 (6) 中,游戏服务器将这些随机位添加到他的密钥中,并使用结果来解密数据。这样一来,攻击者就无法看到打包数据何时发生变化。

这里有没有我忽略的漏洞?

创建的有效负载摘要:

  • 客户端登录凭据(受 SSL 保护),发送到登录服务器
  • 用户信息 + 时间戳 + 临时游戏服务器会话密钥 + 登录服务器使用与游戏服务器共享的密钥加密的摘要,提供给客户端 - 无需修改它 - 将其传递给游戏服务器。应该是抗脾气的,因为:a) 客户端不知道密钥 b) 具有时间戳以避免重新发送相同的数据 c) 验证内容已正确加密的摘要
  • 登录服务器向客户端发送的临时游戏服务器会话密钥以及加密的有效负载。受 SSL 保护。
  • 客户端游戏服务器登录包,由登录服务器接收到的加密包组成。

加密密钥摘要:

  • 临时游戏服务器会话密钥:由登录服务器随机生成,用于加密游戏服务器客户端通信。由登录服务器生成,提供给客户端和游戏服务器。
  • 秘密用户信息加密密钥。在游戏服务器和登录服务器之间共享,用于将用户信息传递给游戏服务器,客户端作为信使。客户端不拥有此密钥。

【问题讨论】:

    标签: security authentication encryption cryptography encryption-symmetric


    【解决方案1】:

    首先我不会使用 RC4。周围有更快和更安全的流密码,所以如果你同时控制客户端和服务器,那么你可能会比 RC4 做得更好。 Fluhrer、Mantin和Shamir攻击只丢弃512字节可能不够,但即使丢弃更多字节,还有Klein的攻击等。我不知道是否值得麻烦。

    其次,确保您生成的密钥是随机的。我知道这似乎很明显,但例如请参阅:http://www.debian.org/security/2008/dsa-1571

    但真正的问题是这部分:“游戏服务器 100% 信任它解密的用户信息。这使得服务器完全解耦,这很好,但如果密钥被泄露,用户可以完全伪造他们的用户信息。 "

    您必须假设用户知道密钥。他的游戏客户端必须知道密钥才能与服务器通信。如果用户可以使用他的真实数据通过 ssl 登录,获取流密码的密钥,然后将他想要的任何信息发送到游戏服务器,那么攻击者所要做的就是获取一个帐户并为所欲为。

    更改密钥的频率无关紧要,因为每次更改时您仍必须将其提供给客户端,因此您不妨在每个字节后更改它,这仍然无关紧要。

    这比使用的密码或密钥生成更重要,因为如果他刚刚得到密钥,没有人会暴力破解密钥。

    您永远不应该相信客户。您应该将客户端数据存储在服务器端并将其与密钥匹配或签署数据并验证它或使用 HMAC 等,因为如果游戏服务器 100% 信任用户信息,那么您迟早会遇到问题。几乎没有办法解决它。

    【讨论】:

    • "您必须假设用户知道密钥。他的游戏客户端必须知道密钥才能与服务器通信。"嗯,客户端只将加密的用户信息从登录传递到游戏服务器。由于客户端从不解密它,因此客户端没有密钥。为客户端提供了一个会话密钥,用于与游戏服务器进行加密通信,但这是一个完全不同的密钥。
    • 为了在 Java 中生成密钥(在这种情况下,游戏服务器和登录服务器都在 java 中)我通常使用 SecureRandom,尤其是 SHA1PRNG。够好吗?
    • 您有什么建议作为 RC4 的替代品?
    【解决方案2】:

    听起来您正在尝试重新发明 SSL。为什么不向每个客户端颁发证书(由您自己的根权限签名),并让他们通过 SSL 连接到游戏服务器,并进行相互身份验证?

    【讨论】:

    • 游戏服务器应该能够同时处理大量玩家。对于 Java 中的服务器,我使用的是非阻塞套接字。不幸的是,这意味着在标准套接字之上实现 SSL。在这样做的过程中,我发现每个连接需要分配大约 32kb,因为 SSL 引擎在 java 中的实现方式。未加密的版本将使用少于 100 个字节。这种内存需求 + Java SSL 实现与非阻塞 IO 非常不匹配的事实让我寻找其他解决方案。
    • @Nuoji 等等,Java 不支持基于异步套接字的 SSL?即使是这样,如果以前没有人解决过这个问题,我会感到震惊。关于开销参数,您需要确定您的威胁模型,以及服务器开销或安全性对您来说更重要。
    • 不,没有内置异步SSL。当然已经实现了,我自己也实现了。我认为这是一个规模问题。当您为 5000 多个同时连接进行设计时,情况会有所不同。
    • @Nuoji 正如我所说,您需要考虑您的威胁模型。如果您关心安全性,则需要使用 SSL,而不考虑额外开销。
    • 我怀疑美国国家安全局或类似机构试图破解它。不过,很可能是一个非常聪明和敬业的骗子。只要消息需要足够的时间来破解(比如一周)就可以了。
    【解决方案3】:

    我了解您不能在游戏服务器和客户端之间使用 SSL,因为您不想再次握手。

    乍一看,协议似乎没问题。也没有重放攻击,因为您确实需要对称会话密钥来做任何有意义的事情。您可以做的最好的事情是切换到 AES 也非常快速且非常安全。我非常怀疑切换到 AES 会影响性能。

    您提到的第一个安全问题要点也不是真正的问题。好吧,这是桌面上所有客户端的一个问题,例如,您的浏览器在通过 HTTPS 通信时遇到了同样的问题。所以你真的不必解决它。如果您想主动监控操纵尝试,您的游戏逻辑必须以某种方式寻找不良行为。您无法通过重新键入来解决它。

    【讨论】:

    • 我想知道加密是否需要那么好。我加密有两个原因:1)它向游戏服务器验证玩家身份 - 通过向游戏服务器显示它知道如何加密数据,它验证它是否已从登录服务器接收到有效的会话密钥。 2)它可以防止随意窃听,这将使攻击者看到对手的游戏玩法。游戏服务器和玩家之间的数据包数量通常很小(每个游戏会话少于 1k 个数据包,每天一个游戏会话),而且信息很快就会在几天内变得毫无价值。 RC4 还能接受吗?
    • @Nuoiji - 当然可以,我可以接受这个论点。因此,实际上 RC4 加密仅告诉您用户已通过身份验证,除此之外,您还获得了免受临时窃听者和临时攻击者的保护。我唯一的建议是明天,如果游戏变得流行并且您在游戏中引入某种货币和商业,那么成为攻击者可能会变得更有吸引力,此时您可能想要加强加密,对吗?如果是这样,如果 RC4 没有给您带来性能提升,为什么还要打扰它呢?如果您也使用 RC4,我理解。
    • RC4 还有两个不错的属性:1) 它适用于较小的密钥,如果我想通过使用密钥 64 来避免客户端的 CCATS 商品分类程序,这很有用-位或更少。 2)它是一个流密码,当协议通常在流上工作时,它非常方便编码。
    【解决方案4】:

    我最后还在 sci.crypt 上发帖,我将尝试在下面总结建议的更改(据我所知),以备不时之需。

    第 1 步:客户端使用凭据向登录服务器发送 HTTPS 请求

    假设凭证采用登录令牌的形式,还要添加一个自分配的唯一 ID。

    第三步:用户信息+RC4会话+时间戳+摘要

    使用可确保完整性的加密算法,而不是显式使用摘要。例如。 AES-GCM 或 AES-CCM。在步骤 1 中添加额外的 id 字段。将 ip 也添加到游戏服务器。

    第四步:将打包好的数据+RC4会话加密密钥+ip地址作为回复发送给游戏服务器。

    将时间戳提供给客户端将使客户端知道会话何时过期。这样可以避免使用过期凭据不必要地连接到游戏服务器。

    第 5 步:客户端打开与游戏服务器的连接,发送带有加密用户信息作为负载的初始未加密 hello 消息。

    将步骤 1 中未加密的自分配 id 添加到有效负载中。

    第六步:游戏服务器解包(3)中打包的数据。它现在知道用户和它应该使用的 RC4 加密密钥。

    游戏服务器将自己的 ip 与加密的 ip 匹配,以及将加密的 id 与客户端提供的 id 匹配。第一个防止用户使用相同的凭据访问不同的服务器。

    第 8 步:如果一切正常,则服务器发送未加密的 LOGIN_OK,然后开始 RC4 加密通信。

    此时游戏服务器无法确定客户端的身份。使用会话密钥并加密nonce + 严格增加会话id + 使用AES-GCM/CCM 登录成功状态并发送给客户端。

    客户端解密并检查登录成功状态。如果这是真的,那么客户端就知道游戏服务器知道会话密钥(GCM/CCM 验证数据包没有被篡改)。客户端返回 sid + nonce。

    服务器验证 sid + nonce 与发送的值相同。

    最后,客户端和服务器通过使用 sid + nonce + salt 对会话密钥进行哈希处理来创建新的会话密钥,从而为后续通信创建密钥,以防止可能的重放攻击。

    关于 RC4

    RC4 中存在漏洞,但由于相当激进的密钥重新调度,因此该方案可能就足够了。但是,有一些更安全、更快速的现代密码,例如 Snow 2.0 或 Trivium。

    【讨论】:

      【解决方案5】:

      只需使用 SSL 连接游戏服务器。现代密码分析已经导致一些更好的加密算法的一些非常快速的实现。例如,经过优化的 AES 实现可以轻松地在任何远程现代机器上以超过 150MB/s 的速度进行加密。此外,虽然 AES 受到高度重视,但我知道它确实有两个弱点,但如果使用得当,这些弱点就会变得微不足道。

      我注意到您没有提及您将在客户端和游戏服务器之间使用高级密钥调度算法。不这样做会使加密算法的弱点更加严重。 SSL/TLS 应该为您安排密钥。

      【讨论】:

      • 有趣。您说的 AES 中的这两个弱点是什么?
      • 查看我对 Nick Johnson 的回复,了解我为什么要避免使用 SSL 连接游戏服务器。你能澄清一下你关于密钥调度算法的文章吗?
      • @user220201 AES 有一个相关的密钥弱点,但如果您执行正确的密钥派生以及所谓的缓存定时攻击,这无关紧要,但这需要窃听者能够在机器进行加密/解密。
      • @Nuoji 在密钥调度部分,我的意思是您需要以窃听者难以预测的方式定期更改加密和身份验证密钥。没有完美的方法可以做到这一点,但有些方法会比其他方法更好。
      • 正如您在描述中看到的,登录服务器创建会话密钥。此密钥可能在 1 分钟或 24 小时内有效 - 我不知道什么是合理的时间。在任何情况下,会话密钥都将从合理安全的伪随机生成。在不同时间为同一用户生成的两个不同会话密钥之间应该完全没有关联。
      猜你喜欢
      • 2010-10-02
      • 1970-01-01
      • 1970-01-01
      • 2010-10-04
      • 1970-01-01
      • 2021-11-27
      • 2016-03-24
      • 2021-12-13
      • 2011-10-15
      相关资源
      最近更新 更多