哈希函数的隐藏危险:长度扩展攻击与服务端验证的安全隐患

    简介LengthExtensionAttack是一种与某些特定类型的哈希函数(如MD5,SHA-1和SHA-2)的特性有关的攻击。简单来说,这种攻击利用了一个事实,即知道H(message)和message的长度,我们可以轻松计算出H(message||padding||extension)而不需要知道message本身。其中“||”表示连接,“padding”是根据哈希函数的规定添加的。这是因为这些哈希函数使用了Merkle-Damgård结构,它将输入切片为多个块,并且每个块的哈希值依赖于前一个块的哈希值。这意味着一旦我们计算出了某个消息的哈希值,就有了一个状态,可以从那里开始并添加更多的块。一种服务端验证模式为方便描述漏洞场景,我们首先假设有这样一种服务端验证模式,即用户尝试登录时,服务端会根据用户的ID、名字以及一个仅服务端知道的30位密钥,通过特定的哈希算法生成一个哈希值,并将其下发给客户端。随后,当客户端尝试访问某些特定接口,例如修改用户权限的接口时,服务端会根据前端POST的角色ID、角色名字、角色权限以及同样的30位密钥,重新生成哈希进行验证。如果上传的哈希与服务端生成的哈希一致,则视为验证通过,并将新的角色权限写入数据库。为便于理解,下面是根据描述写的一些简单的代码做为示例:越权思路由于验证模式存在漏洞,攻击者可以在不知道SecretKey的情况下,通过重新构造交易请求,达到绕过权限验证的目的。

    越权攻击的核心思路在于利用长度扩展攻击的特性。攻击者首先需要获取到原始的哈希值,并通过简单的迭代算法计算出原始数据的长度。一旦得到这些信息,就可以将额外的越权参数添加到原始数据中,并利用相同的哈希算法生成恶意的哈希值。长度扩展攻击原理LengthExtensionAttack发生的原因在于部分哈希函数的内部机制。这些函数在处理输入数据前,首先将数据分割成固定长度的块,然后在每个块的末尾进行填充以满足特定的要求。这种设计导致攻击者可以在知道原始消息哈希值和长度的情况下,通过填充和附加新数据,构造出新的有效哈希值。以SHA-256为例,其工作在512比特的块上。对于长度不是512比特的倍数的数据,需要进行填充操作。其填充规则如下:1.在数据的末尾添加一个“1”比特;2.添加一定数量的“0”比特,使得数据的长度模512等于448(详细内容见[1]);3.在最后面添加一个64位长的块,表示原始数据的长度。

    简而言之,将一个“1”后面跟着m个“0”,再加上一个64位或128位的整数,附加到消息的末尾,以生成长度为512*n的填充消息。附加的整数是原始消息的长度。然后,填充消息将被哈希函数处理为n个512位的块。构造方法在这个示例中,我们将以上面图片提到的代码做为一个特定的场景,其中数据字符串为data="user_id=1&user_name=aa",密钥为SecretKey="Length_extension_attack_secret"。服务端会解析上传的数据中的data字段,并通过分隔符&解析出所需的参数user_id和user_name。如果存在role字段,服务端也会获取该字段的值。然后,服务端会将所有字段与SecretKey进行哈希运算,并与上传的验证哈希进行比较。如果哈希值一致,则认为参数符合规则,并直接使用。首先,我们通过登录loginHandler接口获取根据data和SecretKey使用SHA-256生成的哈希值hash="37d310d3465506486431fb2c2eb163f0f470479703f66dc9e5fdead8a3390c68"。

    接下来,我们将探讨破解的难度。以我们的测试情况为例,根据长度扩展攻击的原理,只要知道H(message)和message的长度,我们就可以通过长度扩展攻击添加新的数据。原来的message=SecretKey+data,现在我们手上已经有H(message),只需知道message的长度,就可以构造一个新的哈希值。由于SecretKey是一个30位的密钥,只需经过30次迭代,就可以得知真正的message的长度。因此,我们可以很容易地构造出一个新的哈希值。由于我们需要使用admin的权限,所以我们要将恶意的字段"&role=admin"拼接到原来的数据中。我们可以利用长度扩展攻击的特性,在不知道SecretKey的情况下,添加新的数据并生成一个新的哈希值。这里使用一个已经实现此功能的库[2]来完成测试。再使用工具生成新的哈希值。

    由于adminActionHandler的接口验证是根据上传的user_id,user_name和role来验证hash的,我们这时候上传的数据是user_id=1,user_name=aax80x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x01x70以及role=admin,如下图所示:哈希值为84ae4ae437eeabf3bd8a26294392770b86f64a81998194156ac003d58a21acd0。之后就可以调用adminActionHandler接口,服务端收到数据后,会把上传的哈希与sha256(SecretKey+fakeData)进行对比,通过验证之后将会执行一些敏感操作。这样,我们就成功地利用长度扩展攻击绕过了服务端验证,并实现了越权操作。其他可能的攻击场景1.文件完整性验证:如果文件的完整性是通过连接密钥和文件内容,然后对其进行哈希来验证的,那么攻击者可能会扩展文件并生成一个有效的哈希,从而绕过完整性检查;2.Web应用安全:在Web应用中,如果使用了易受长度扩展攻击的哈希函数来验证用户提交的数据,攻击者可能会利用这一点来提交恶意数据;3.数字签名:在某些数字签名方案中,如果签名是通过连接私钥和消息,然后对其进行哈希来生成的,那么攻击者可能会扩展消息并生成一个有效的签名;4.密码存储:虽然不常见,但如果密码是通过连接密钥(例如盐)和密码,然后对其进行哈希来存储的,那么攻击者可能会尝试使用长度扩展攻击来破解密码。如何防范1.选择不易受长度扩展攻击的哈希函数,例如SHA-3;2.使用HMAC:HMAC需要一个密钥和一个消息作为输入,输出的结果既依赖于密钥,也依赖于消息,因此攻击者在不知道密钥的情况下无法进行长度扩展攻击;3.加强权限验证:在服务端增加额外的权限验证步骤,例如使用多因素认证。以下是一些常用的Hash算法的特性:算法碰撞抵抗选择前缀碰撞攻击预映像抵抗长度扩展攻击MD52^182^392^123.4易受攻击SHA-12^61.22^63.42^160易受攻击SHA-256(SHA-2)2^65.5-2^254.9易受攻击SHA-512(SHA-2)2^32.5-2^511.5易受攻击SHA-32^50-未知不易受攻击BLAKE2s2^112-2^241不易受攻击BLAKE2b2^224-2^481不易受攻击结语对于长度扩展攻击,一种有效的防护措施是使用不受此类攻击影响的哈希函数,例如SHA-3和BLAKE2。另外,还可以通过HMAC(密钥散列消息认证码)结构来进行防护。这些措施可有效提高系统的安全性,确保数据完整性和应用程序的稳定性。参考链接:[1]https://www.rfc-editor.org/rfc/rfc6234#page-8[2]https://github.com/skerkour/kerkour.com/tree/main/blog/2023/sha256_length_extension_attacks