加载中...
不想等待可以点我关掉

长度扩展攻击

采用 Merkle–Damgård 结构(MD结构、迭代结构)的哈希函数,比如 MD5、SHA-1、SHA-256,会在处理过程中将长消息分块,逐块进行压缩处理:

  1. 填充(Padding):把任意长度的数据填充成固定块大小的整数倍。
  2. 分块:把数据分成若干块。
  3. 初始化:设定一个初始状态(Initialization Vector,IV、初始向量)(初始向量是公开的、预先定义的)。
  4. 循环调用压缩函数:把初始状态和第一块丢进压缩函数,得到状态 a;再把状态 a 和第二块丢进去,得到状态 b……直到最后一块处理完,输出最终哈希值。
图解
图解

可以注意到,B可以是“块一和块二”的最终输出,也可以是“块一、块二、块三”的中间状态。
又因为每次循环逻辑固定,当攻击者获取到B时,攻击者可以构建自己的“块三”结合B来在不知道密钥(假设密钥直接拼接在待哈希内容前,且完全位于块一内)生成合法的最终输出

HMAC

哈希运算消息认证码,Hash-based Message Authentication Code

HMAC(K,m)=H((K⊕opad)∥H((K⊕ipad)∥m))HMAC(K, m) = H( (K \oplus opad) \parallel H( (K \oplus ipad) \parallel m ) )

其中K为固定密钥,而原始密钥 KK 又会被分别与两个固定的常量(ipad 和 opad)进行异或运算:

  1. K1=K⊕ipadK_1 = K \oplus ipad
  2. K2=K⊕opadK_2 = K \oplus opad

随后,消息 mm 和 K1K_1 拼接,整体进行哈希计算,结果和 K2K_2 再做一次拼接与哈希

图解
图解

HMAC的处理过程包括使用哈希函数,两者不是平级关系

解决的问题:单次哈希会“暴露”中间状态,攻击者可以通过正常情况下的输出,猜测并构建恶意载荷,在尾部附加。由于中间状态是由正确的密钥和上一部分消息构建的,此时服务端会将其视为有效的结果

而HMAC通过两次哈希处理,套娃,并且所用的密钥不一样。导致攻击者即便在最终输出基础上效仿前者进行拼接,也只能更改第二次哈希的结果,第一次哈希产生的最终输出 AA (HMAC的中间状态)无法被更改。导致注入恶意载荷的消息在第一次哈希时产生的 AA 就不一样,导致最终输出不一致,防范了长度扩展攻击。