项目 | 描述 |
---|---|
搜索引擎 | Bing、Google |
AI 大模型 | 文心一言、通义千问、讯飞星火认知大模型、ChatGPT |
PHP 手册 | PHP Manual |
wsfgrdgh | PHP8中字符串与数字的比较更智能 |
PHP RFC 文档 | Saner string to number comparisons |
超模君 | 两度破译“白宫密码”,让美国政府部门崩溃,却称自己是抱娃敲代码的普通妈妈 |
项目 | 描述 |
---|---|
PHP | 5.5.0 、5.6.8 、7.0.0 、7.2.5 、7.4.9 、8.0.0 、8.2.9 |
在 PHP 中,强类型比较运算符
是指对操作数进行比较操作时,不单单只比较 操作数的大小
,还比较 操作数所属的数据类型是否相同
。
与强类型比较符相对的是 弱类型比较运算符
,弱类型比较运算符是指 PHP 在进行比较操作时,当操作数的数据类型不同时
,PHP 将尝试将 依据一定的规则将操作数的数据类型进行统一
。
举个栗子
# 强类型比较运算符
var_dump('4949' == 4949);
//在 PHP8 版本中运行
//'4949Hello' == 4949
//得到的结果将为 false
var_dump('4949Hello' == 4949);
# 弱类型比较运算符
var_dump('4949' === 4949);
var_dump('4949Hello' === 4949);
执行效果
bool(true)
bool(true)
bool(false)
bool(false)
MD5 算法的 哈希输出空间
相对较小,仅有 128
位(仅能容纳 128 位二进制数据),而 输入空间是无限的
,这种 输入与输出的不匹配性
导致了哈希碰撞的 可能性
。攻击者可以使用 巧妙构造的输入数据
,通过精心选择的 碰撞攻击算法
,找到 具有相同哈希值的不同输入
。
在继续讲解前,先来看一段代码。倘若在安全竞赛中你需要绕过一个类似如下 PHP 代码中的判断语句:
$user_input = "I'm a secret.";
$user_input_1 = "I'm a secret too.";
if ($user_input !== $user_input_1 && md5($user_input) === md5($user_input_1)) {
print('Win');
}
上述代码 允许用户进行两次输入
,在后续的判断语句中,PHP 将采用 强类型比较运算符
判断用户的两次输入是否相同 且
这两次输入的 MD5 哈希结果
是否相同。这意味着
我们需要寻找到 能够产生哈希碰撞的两个数据
。这样的数据当然能够从网络中获取到,但想必我们都希望使用一种更为专业的手段解决这个问题♂️。并且,从网络中查找到能够发生哈希碰撞的几个数据来绕过判断语句这一方案仅在 $user_input
与 $user_input_1
均为用户的输入数据时生效,假如 $user_input
与 $user_input_1
中的 任意一个变量的内容由 PHP 程序指定
,这一方案即土崩瓦解。
王小云(Xiaoyun Wang)院士
是中国首屈一指的密码学专家,因她在 哈希函数密码分析方面
的贡献而广受赞誉。她是几种流行的密码算法潜在弱点的发现者之一,其中包括对 MD5
、SHA-0
和 SHA-1
哈希函数的攻击。
基于 Hash 函数的 MD5
和 SHA-1
是由美国标准技术局(National Institute of Standards and Technology,NIST)颁布的,是 当时国际上公认最先进、应用范围最广的两大重要算法
。也正如此,MD5
与 SHA-1
被称为白宫密码。
2004 年,王小云院士在密码学大会上宣布 四个国际通用
的哈希算法 MD5
、 HAVAL- 128
、MD4
和 RIPEMD
已被破解,震惊全球。在会上,王小云公布了一种方法,可以更有效地找到哈希函数的两个不同输入,这两个输入会产生相同的哈希值(这一现象被称为哈希冲突)
。
理论上,为了找到能够产生哈希碰撞的另一数据,可能需要尝试的次数接近 2
的 80
次方。但是,王小云的方法大大减少了这个数字,虽然仍然需要巨大的计算量,但这个方法确实暴露了MD5 的潜在弱点。
美国对于王小云的研究大为震撼,却故作镇定的认为新研究出的 SHA-1
加密算法绝不可能被攻破。然而仅在两个月后,SHA-1
便被王小云成功破解。原本在密码界还是一张白纸的中国,一下子成了密码学界不可忽视的新星✨。
在现代社会中,短视和即时回报的诱惑无处不在。然而,真正的突破和伟大的成就往往源于深入钻研、持续的努力和对目标的坚韧不拔
。王小云成功破译 宫密码正是这样一个令人震撼的例证。
密码学的求学道路,王小云走了十年。那十年,当许多人追求短期的荣誉、金钱和地位,王小云却选择了 一条不同的道路
,她选择了对自己的研究领域保持深厚的热情和对解决问题的决心。
使用王小云院士提供的 MD5 破解方案,可以在 数个小时内(依计算机配置而定)
完成 MD5 的破解。但实际上
,在我们这个例子中,还无需使用到这一方案。
Warning
是 PHP 中的一种 异常类型
,常产生于一些需要 提醒开发者异常的存在但又没有必要立即停止程序的情况
中。
PHP 中的 md5()
函数允许你使用 数组
作为该函数的参数,md5()
函数对于 任何数组
都将返回 NULL
。对此,请参考如下示例:
$result = md5([1, 2, 3]);
$result_1 = md5(['Hello', ' ', 'Wrold']);
$result_2 = md5(['One' => 'Hello', 'Two' => ' ', 'Three' => 'World']);
var_dump($result);
var_dump($result_1);
var_dump($result_2);
执行效果
上述示例代码中向 md5()
函数传递了 三个不同的数组
,在 md5()
函数的处理下,它们都无例外的转化为了 NULL
。
Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 4
Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 5
Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 6
NULL
NULL
NULL
PHP Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 4
PHP Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 5
PHP Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 6
回到我们最初探讨的问题上来:
$user_input = "I'm a secret.";
$user_input_1 = "I'm a secret too.";
if ($user_input !== $user_input_1 && md5($user_input) === md5($user_input_1)) {
print('Win');
}
想必各位此时已经对上述代码中的判断语句的绕过方式已经有了方案,即将 $user_input
与 $user_input_2
这两个变量赋值为 两个不相等的数组
即可。
对此,我们做出了下述调整:
$user_input = ['One' => 'Hello', 'Two' => ' ', 'Three' => 'World'];
$user_input_1 = [1, 2, 3];
if ($user_input !== $user_input_1 && md5($user_input) === md5($user_input_1)) {
print('Win');
}
执行结果
能够观察到,我们已经绕过了 MD5 函数的限制,成功执行了 if
语句包含的代码。
PHP Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 7
PHP Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 7
Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 7
Warning: md5() expects parameter 1 to be string, array given in C:\test.php on line 7
Win
不同于其他版本(PHP8 以下版本),PHP8
不允许在 md5()
函数中使用数组。倘若您在 md5()
函数中使用数组,PHP 将抛出 Fatal Error
异常,程序将立即终止。
对于我们刚刚找到的绕过方案:
$user_input = ['One' => 'Hello', 'Two' => ' ', 'Three' => 'World'];
$user_input_1 = [1, 2, 3];
if ($user_input !== $user_input_1 && md5($user_input) === md5($user_input_1)) {
print('Win');
}
在 PHP 中将得到如下结果:
PHP Fatal error: Uncaught TypeError: md5(): Argument #1 ($string) must be of type string, array given in C:\test.php:7
Stack trace:
#0 C:\test.php(7): md5(Array)
#1 {main}
thrown in C:\test.php on line 7
Fatal error: Uncaught TypeError: md5(): Argument #1 ($string) must be of type string, array given in C:\test.php:7
Stack trace:
#0 C:\test.php(7): md5(Array)
#1 {main}
thrown in C:\test.php on line 7