针对 Mac 和签名的规范化攻击

2021-07-30 17:25:27

当将数据提供给 MAC 或数字签名计算中使用的哈希函数的协议无法确保整个协议的某些属性时,就会发生规范化攻击。规范化攻击的教科书示例是针对诸如 MD5 之类的哈希函数的长度扩展攻击——它以破坏 Flickr API 签名的安全性而闻名。但是还有一种更有趣的攻击需要考虑,它会影响安全令牌格式(PASETO、DSSE 等)的设计,并且经常出现在人们试图扩展认证加密 (AE) 的基本概念以包括额外的认证(但未加密) ) 数据(从而产生 AEAD 模式)。让我们从一个基本的 AE 定义开始,然后将其扩展到 AEAD,然后打破我们的扩展。之后,我们可以考虑将其做得更好的策略。我们经常将这种形状称为“CBC+HMAC”(尽管这与称为 CBC-MAC 的非常不同的想法混淆了一些错别字)。当 CBC+HMAC 与具有 256 位密钥和 HMAC-SHA2 的 AES 分组密码一起使用时,它变为 AES-256-CBC+HMAC-SHA256。多嘴啊!在现代设计中,AES-CTR 通常比 AES-CBC 更可取,因为您不必处理填充(或填充预言机)。

现在大多数系统更喜欢 GCM 而不是 CBC+HMAC 或 CTR+HMAC。我不喜欢 AES-GCM(特别是如果您的用例是“没有硬件加速的支持平台”),但对于大多数应用程序来说,它几乎不是最糟糕的选择。 AES-GCM是专用的AEAD模式,而CBC+HMAC和CTR+HMAC只提供AE。附加数据(AEAD 中的 AD)的主要目的是将加密的有效负载(密文 + 身份验证标签)绑定到给定的上下文。这对于减轻混淆代理攻击非常有帮助。至关重要的是,这些额外数据并未加密。 (至少,在这个级别上;通过 HTTPS 进行通信可能是明智的!)生成一个与块密码的块大小相等的随机随机数。 (AES 为 16 字节。)解密基本上反向运行第 3 步和第 2 步:重新计算 MAC(以恒定时间!),解密密文,返回明文。扩展此设计以支持其他已验证数据的最明显方法是将其附加到密文中。生成一个与块密码的块大小相等的随机随机数。 (AES 为 16 个字节。)

计算 IV 的 HMAC-SHA2 输出,然后是来自步骤 2 的密文,然后是附加的已验证数据。假设您构建了这个扩展协议来加密看起来像 URI 字符串的有效负载,但想要将令牌绑定到给定的浏览器会话,因此您使用 HTTP User-Agent 标头作为 AAD。所以这是一个聪明的攻击:如果你可以将字节从有效负载转移到你的用户代理字符串的前缀中,它们将产生相同的 HMAC 标签。攻击者可以通过将其添加到包含在其 HTTP 请求中的 User-Agent 来截断尽可能多的有效负载。 ...无需使现有的身份验证标签无效——只需确保将密文的最后 16 个字节添加到您的用户代理并从有效负载中删除即可。更广泛地说,任何时候您将多部分消息输入散列函数时,如果您不小心将其输入散列函数的方式,就可能引发琐碎的冲突。这显然是正确的,因为哈希函数是确定性的:相同的输入将始终产生相同的输出。如果您可以控制多部分消息的一个或多个部分,您可以碰撞输入——从而在输出中创建碰撞。

这可能会影响任何依赖于哈希函数的协议,但最明显的是,HMAC 和数字签名算法都在范围内。但是,“小心”是什么样子的呢?让我们看一个安全的例子。早些时候我提到了 PASETO 和 DSSE。他们都有“PAE”算法的概念,旨在防止规范化攻击。如果您输入不同数量的碎片,则计数(前 8 个字节)会有所不同。如果您尝试将数据从一块移动到另一块,您将为两块生成不同的长度,这不会对散列函数产生输入冲突。没有长度前缀,我们与上面定义的 CTR+HMAC 扩展没有什么不同。如果没有计数前缀,就有可能丢弃碎片,然后在其他人的有效载荷中包含一个虚拟的“长度”以创建输入碰撞。

毫不奇怪,我发现 DSSE 对 PAE 的定义有些奇怪。使它们免于规范化攻击的唯一方法是片段的数量是恒定的。如果片段的数量是可变的(例如,如果 KEYID 可选地包含在签名中,但如果不存在,他们忘记始终包含硬编码的 0 长度),您可以通过构建两个不同的消息来击​​败他们的 PAE 风格在数字签名算法中产生相同的散列。这是因为 DSSE 定义中不包括件数。 (如果它们曾经支持可变数量的组件,并且未能在签名中包含计数,它们将很容易受到攻击。) 为什么要使用 PAE?因为我们需要一种明确的方式来序列化两个字段,payloadType 和 payload。 PAE 已经被记录并且足够好。无需重新发明轮子。 ……然而,他们实际上并没有使用 PASETO 对 PAE 的“已经记录并且足够好”的定义。攻击这种设计的唯一可能的方法是瞄准整数溢出,这将需要发送至少 2^63 个字节 - 在这一点上,您更有可能对目标进行 DDoS 攻击而不是成功。

规范化攻击在专家圈之外的加密协议设计中没有得到广泛理解或广泛认可的风险(尽管许多应用程序安全人员至少知道特定实例,即长度扩展)。缺乏知识转移的部分原因是所有 AEAD 模式都通过设计来防御它,并且大多数手工验证的加密结构不会打扰额外的验证数据,大多数自制的加密协议甚至不进行验证他们的密文正确,并且……我希望你明白这一点。一直有未解决的问题。指望不是这个特定领域的专业专家的人都能把他们都做对,坦率地说是不合理的。