CBC 位翻转攻击详解

加密并不意味着你的数据免受篡改。

许多开发者都会犯这个错误。他们认为如果攻击者无法读取数据,就无法更改数据。这是错误的。密码学将机密性(secrecy)和完整性(integrity)视为两个不同的任务。

CBC 位翻转攻击证明了这一点。攻击者无需知道你的密钥即可更改你的数据。

其工作原理如下:

AES 并不是将数据作为一个大块进行加密。它将数据分解为 16 字节的块。在 CBC 模式下,这些块会链接在一起。第一个块的加密输出会混入第二个块的明文中。

这种链式结构在解密过程中产生了一个弱点。为了获取第 2 块的原始文本,服务器会对该块进行解密,并将其与第 1 块的密文结合。

攻击者可以利用这一点:

攻击者不需要读取消息。他们只需翻转位(bits)来改变最终结果。

假设有一个旧的 Web 应用使用加密 Cookie 来管理会话。一个 Cookie 可能包含: userid=994;role=user;

攻击者拦截了这个 Cookie 并翻转了密文中的位。他们发送大量请求,直到服务器接受其中一个。由于服务器只检查数据是否能成功解密,它会处理修改后的文本。突然间,解密后的字符串变成了: userid=994;role=admi;

攻击者现在获得了管理员权限。他们从未读取过密钥或原始 Cookie。

错误在于假设加密可以保证完整性。

要解决这个问题,请使用像 AES-GCM 这样的认证加密(Authenticated Encryption)。它会创建一个加密标签(cryptographic tag)。这个标签就像一个封条。如果攻击者哪怕只修改了一个位,封条就会破损。服务器会立即拒绝该数据。

如果你必须使用 CBC,请使用“先加密后 MAC”(Encrypt-then-MAC)架构。为密文创建一个认证码(authentication code),并在开始解密之前对其进行验证。

秘密数据并不总是可信的数据。在使用数据做出决策之前,务必证明数据未被篡改。

CBC 位翻转攻击详解:为什么仅靠加密无法保证完整性

当我们谈论加密时,我们通常是在谈论机密性 (Confidentiality) —— 即确保只有授权人员才能读取信息。然而,加密并不等同于完整性 (Integrity) —— 即确保信息在传输过程中没有被篡改。

在密码学中,一个常见的误区是认为只要数据被加密了,它就是安全的。但如果攻击者可以修改密文,即使他们无法解密它,他们仍然可以破坏数据的含义。这就是 CBC 位翻转攻击 (CBC Bit-Flipping Attack) 的核心所在。

什么是 CBC 模式?

密码块链接 (Cipher Block Chaining, CBC) 是一种常用的对称加密模式。在 CBC 模式中,每个明文块在加密之前都会与前一个密文块进行异或 (XOR) 运算。

其加密过程如下:

  1. 第一个明文块与初始化向量 (IV) 进行异或,然后进行加密。
  2. 对于后续的每个块,当前的明文块先与前一个密文块进行异或,然后再进行加密。

解密过程则正好相反:

  1. 当前密文块被解密。
  2. 解密后的结果与前一个密文块(或 IV)进行异或,从而得到原始明文。

用数学公式表示,第 $i$ 个明文块 $P_i$ 的解密公式为: $$P_i = D_k(C_i) \oplus C_{i-1}$$

其中:

位翻转攻击是如何工作的?

请注意解密公式中的 $\oplus C_{i-1}$。这意味着,前一个密文块中的任何变化,都会直接且可预测地影响当前明文块的解密结果。

如果攻击者翻转了密文块 $C_{i-1}$ 中的某一个比特(将 0 变为 1,或将 1 变为 0),那么在解密 $C_i$ 时,对应的明文块 $P_i$ 中相同位置的比特也会发生翻转。

虽然这种操作会使 $C_{i-1}$ 块本身在解密时变成“乱码”(因为 $C_{i-1}$ 块在解密时依赖于 $C_{i-2}$),但攻击者通常并不关心 $C_{i-1}$ 的内容,他们只关心通过修改 $C_{i-1}$ 来精确控制 $P_i$ 的内容。

实际案例:篡改权限

假设一个 Web 应用程序使用 CBC 模式加密存储用户的 Cookie,Cookie 的内容如下:

user_id=123;admin=0

假设这个明文被分成了两个块(为了简化演示):

当这些块被加密后,我们得到了密文 $C_1$ 和 $C_2$。

攻击者的目标是将 admin=0 修改为 admin=1。由于 admin=0 位于第二个明文块 $P_2$ 中,攻击者只需要修改第一个密文块 $C_1$ 中的特定比特。

攻击步骤:

  1. 识别目标比特:攻击者知道 $P_2$ 中 0 的位置。
  2. 计算翻转:攻击者通过异或运算,修改 $C_1$ 中对应的比特,使得解密后的 $P_2$ 中的 0 变成 1
  3. 发送篡改后的密文:攻击者将修改后的 $C_1'$ 和原始的 $C_2$ 发送给服务器。

结果: 服务器解密时:

如果应用程序逻辑不够健壮(例如,它只检查 admin 字段,而忽略了 $P_1$ 中的乱码),攻击者就成功获得了管理员权限!

如何防御?

仅仅依靠加密是不够的。为了防止此类攻击,你必须确保数据的完整性

1. 使用消息认证码 (MAC)

最标准的方法是使用 Encrypt-then-MAC 方案。在加密数据后,使用一个独立的密钥对整个密文计算一个 HMAC(基于哈希的消息认证码)。

2. 使用认证加密 (AEAD)

现代密码学推荐使用 AEAD (Authenticated Encryption with Associated Data) 模式,例如 AES-GCM

AEAD 模式将加密和完整性验证集成到了同一个算法中。它不仅提供机密性,还会生成一个认证标签(Authentication Tag)。如果密文在传输过程中被修改,解密过程会自动失败。

总结