使用密码 1注册,然后使用密码 2登录。如果你能成功登录,则说明存储使用指定算法对密码进行哈希,并且 PHP 使用 == 来比较它们(适用于 MD5、SHA-1 和明文)。
对于 MD5、SHA-1 和 SHA-2 系列,它利用了众所周知的技巧(这实际上是一个有文档记载的特性,参见 PHP 类型比较表 和 浮点数):在 PHP 中 '0e1' == '00e2' == '0'。这只是将其用于实际用途。任何密码都匹配列表中的任何其他密码。这与整数字符串溢出为浮点数的技巧不同,只需辨别这两行代码之间的区别。
以下是所有具有魔法哈希的算法:
md5(md5(password))引用 @0xb0bb 的话:“魔法哈希除了密码比较之外还有其他应用(例如缓存层或从哈希函数输出派生的数据),在这些场景中更容易发现这些已知不安全、不太知名以及伪哈希算法。”
对于明文,它使用了各种转换技巧。第一个密码只会匹配第二个密码。这些技巧按允许它们的 PHP 版本分组。
bcrypt 会将密码截断为最大长度 72 个字符。如果两个密码的前 72 个字符匹配,则密码匹配。
descrypt(传统 UNIX DES crypt)会将密码截断为最大长度 8 个字符。如果两个密码的前 8 个字符匹配,则密码也会匹配,参见“General cross-check”一节。
如果你使用长度超过 64 字节的密码,并使用 PBKDF2-HMAC-SHA1 对其进行哈希,它会先被 SHA1 预哈希,因此 PBKDF2-HMAC-SHA1(password1) === PBKDF2-HMAC-SHA1(password2),因为 sha1(password1) === bin2hex(password2)。对于 PBKDF2-HMAC-SHA224 和 PBKDF2-HMAC-SHA256,也会应用类似的预哈希。
目前每个算法中只有一个魔法哈希,这要感谢 Norbert Tihanyi,希望将来会添加更多。
在 PHP 中比较任何内容*时,请使用 ===,而不是 ==。在 PHP 中请使用 password_hash() 和 password_verify() 进行密码哈希,不要使用 MD5 或 SHA-1。*在比较哈希时请使用 hash_equals()。
这一切都始于这条推文。2014 年 2 月,我生成了 QNKCDZO 和 240610708,此后它便传遍了整个互联网。只需谷歌一下。