长度扩展攻击
采用 Merkle–Damgård 结构(MD结构、迭代结构)的哈希函数,比如 MD5、SHA-1、SHA-256,会在处理过程中将长消息分块,逐块进行压缩处理:
- 填充(Padding):把任意长度的数据填充成固定块大小的整数倍。
- 分块:把数据分成若干块。
- 初始化:设定一个初始状态(Initialization Vector,IV、初始向量)(初始向量是公开的、预先定义的)。
- 循环调用压缩函数:把初始状态和第一块丢进压缩函数,得到状态 a;再把状态 a 和第二块丢进去,得到状态 b……直到最后一块处理完,输出最终哈希值。
可以注意到,B可以是“块一和块二”的最终输出,也可以是“块一、块二、块三”的中间状态。
又因为每次循环逻辑固定,当攻击者获取到B时,攻击者可以构建自己的“块三”结合B来在不知道密钥(假设密钥直接拼接在待哈希内容前,且完全位于块一内)生成合法的最终输出
HMAC
哈希运算消息认证码,Hash-based Message Authentication Code
其中K为固定密钥,而原始密钥 又会被分别与两个固定的常量(ipad 和 opad)进行异或运算:
随后,消息 和 拼接,整体进行哈希计算,结果和 再做一次拼接与哈希
HMAC的处理过程包括使用哈希函数,两者不是平级关系
解决的问题:单次哈希会“暴露”中间状态,攻击者可以通过正常情况下的输出,猜测并构建恶意载荷,在尾部附加。由于中间状态是由正确的密钥和上一部分消息构建的,此时服务端会将其视为有效的结果
而HMAC通过两次哈希处理,HMAC的中间状态)无法被更改。导致注入恶意载荷的消息在第一次哈希时产生的 就不一样,导致最终输出不一致,防范了长度扩展攻击。


