领先一步
VMware提供培训和认证,以加速您的进步。
了解更多开发人员经常错误地使用加密来尝试提供身份验证。例如,RESTful 应用程序可能会错误地使用加密 Cookie 来嵌入当前用户的身份。
错误在于加密只能用于保密,而签名用于验证消息的真实性。在这篇文章中,我将解释并举例说明为什么加密不能保证真实性。
如果您只想查看代码,可以随意跳到最后,其中包含一个演示此漏洞的示例 Java 应用程序。
假设我们想要避免在会话中查找用户,而是想将用户信息嵌入到 Cookie 中。由于 Cookie 可以被恶意用户修改,我们需要能够验证提供的 Cookie 是否是由我们的应用程序服务器创建的。
为了防止用户篡改 Cookie,我们错误地决定使用AES 加密和CBC 模式来加密 Cookie,而不是对 Cookie 进行签名。我们的 Cookie 正确加密(但错误地未签名)如下所示
Cookie = Base64String( IV, aes_cbc(k, IV, plainText) )
这样
**注意**:将 IV 与加密文本一起以明文形式包含在内是安全且常见的做法。由于 IV 是固定数量的字节,因此可以轻松地从组合的 IV,encrypted_value byte[] 中提取它。
在我们进一步讨论之前,重要的是要理解异或运算 (XOR)。为了复习您的记忆,以下是 XOR 的真值表
A | B | 输出 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
为了理解我们如何模拟另一个用户,我们首先需要了解一些 AES/CBC 的工作原理。AES 是一个分组密码,这意味着我们的消息被分成固定大小的块,然后对每个块执行操作。
在解密 AES/CBC 时,第一个块的解密值与 IV 进行异或运算。例如,以下情况成立。
decrypt(k, encrypted_first_block) XOR IV = plaintext_first_block
为了更好地理解,让我们来看一个具体的例子。假设以下情况成立
**注意**:我们的示例通过使用 8 位而不是实际的 128 位块大小来简化。这使得人类更容易理解。
这意味着我们的 plaintext_first_block 将是 01110111(在ASCII 中为“w”)。我们的工作如下所示
decrypt(k, encrypted_first_block)
XOR IV
------------
plaintext_first_block
11011101
XOR 10101010
------------
01110111 // "w" ASCII
根据以上信息,我们可以修改解密值。具体来说,给定
我们可以计算一个名为 IV' 的修改后的 IV,它将与原始有效加密值组合以模拟另一个用户。
第一步是通过用 first_block_plaintext 与 IV 进行异或运算来消除 IV 中的所有位,从而计算 decrypt(k, encrypted_first_block) 的未知值。我们的工作如下图所示
IV
XOR plaintext_first_block
------------
decrypt(k, encrypted_first_block)
10101010
XOR 01110111
------------
11011101
最后一步是通过执行 decrypt(k, encrypted_first_block) XOR desired_plaintext_first_block 来计算 IV'。同样,我们的工作如下图所示
decrypt(k, encrypted_first_block)
XOR desired_plaintext_first_block
------------
IV'
11011101
XOR 01100001 // "a" ASCII
------------
10111100
我们现在可以验证提供 IV'(而不是 IV)以及原始加密值将导致“a”而不是“w”。
decrypt(k, encrypted_first_block)
XOR IV'
------------
desired_plaintext_first_block
11011101
XOR 10111100
------------
01100001 // This is "a" ASCII
这表明,如果我们提供 IV'(而不是 IV)以及原始加密值,它将被解密为“a”。
既然我们已经了解了如何创建修改后的 IV 来随意更改我们的加密值,那么让我们探讨一下这如何应用于我们作为用户进行身份验证,然后修改我们的加密 Cookie 来模拟另一个用户。
在修改解密值部分,我们提到在执行漏洞利用之前我们需要一些信息。让我们看看如何使用加密 Cookie 获取漏洞利用所需的信息
现在我们有了必要的信息,并且了解了如何修改加密值,很容易看出我们可以模拟任何我们想要的用户。只要我们拥有一个有效的帐户,我们就可以创建一个 IV',将加密 Cookie 中的用户名更改为我们选择的所需用户。
不相信这个漏洞?通过运行github 上的示例项目来查看演示。要运行该示例,请将其作为 Maven 项目导入到您最喜欢的 IDE 中,然后运行demo.Main类。
您将观察到我们以“winch”身份进行身份验证,但能够修改加密 Cookie 以模拟名为“admin”的用户。
我希望此时您已经相信加密并非提供身份验证的有效方法。相反,我们需要确保cookie已签名。一种解决方案是使用带身份验证的加密,它提供机密性、完整性和身份验证。
请记住,仅仅对我们的cookie进行签名并不能保证其安全。还存在其他攻击媒介,例如重放攻击,必须解决这些问题才能使解决方案安全。
我们必须认识到,安全措施难以实现,不应自行实施,甚至不应由少数个人实施。相反,安全措施最好在能够相互检查错误的社区中实施。