PHP中的弱相等和强相等

入门级理解,没啥含金量:)


本人的一点拙见。

先看下GPT对弱相等和强相等的解释:

1
2
3
4
5
在PHP中,弱相等(==)和强相等(===)是用于比较两个值的操作符,它们有以下区别:

1.弱相等(==):弱相等用于比较两个值是否相等,不考虑值的数据类型。如果两个值在转换后相等,则返回true,否则返回false。弱相等会自动进行类型转换,例如将字符串转换为数字进行比较。

2.强相等(===):强相等用于比较两个值是否相等,且要求两个值的数据类型也相同。除了比较值是否相等外,还要求比较的两个值的数据类型也相同。如果值和数据类型都相等,则返回true,否则返回false。强相等不会进行自动类型转换

在弱相等比较中,不考虑数据类型转换后相等返回true,否则返回false。所以整型、浮点型、字符串、布尔型等均可比较,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//字符串和整型或浮点型比较,字符串若以数字开头则从开头截取到字母出现的位置:
'111' == 111 //True
'111abc' == 111 //True
'111admin' == 111.000000 //True
'notbad3333' == 0 //True
//布尔型与字符串和整型及浮点型均可相互比较:
True == 'hello world!'//True
True == '123abc' //True,字符串里面只要不是单个0,任何组合(哪怕是0.0)都与True弱相等
True =='0.0000' //True
False == 0 //True
False == 0.0 //True,0.0000等同理
False == null //True
False =='0'//True
False =='' //True
False ==
//科学计数法的相关比较,并拓展到MD5加密比较
0e333 == '0e111'//True
'0e321'=='0e789'//True
//比如两个东西加密后均以0e开头,那他们就是弱相等的
//拓展到is_numeric的绕过,很经典的是让你输入一个东西(GET或POST传,这个东西不能是数字却要大于或小于或等于某个特定的数字)
//注意虽然`0==null==false`成立,但不能因为`'notbad3333' == 0`就推出`'notbad3333' == null/false`!

在强相等中,不光要求值相等类型还要相等。如果想要绕过两个md5的强相等:

1
2
3
4
5
6
7
8
9
10
11
12
//数组法
<?php

$flag = "oh you find me!";
$a = $_GET['a'];
$b = $_GET['b'];
if ($a != $b && md5($a) === md5($b)) {
echo $flag;
}

?>//可用GET传?a[]=a&b[]=b,MD5没法给数组加密会返回null(报错),但这时两个null满足了强相等。
//碰撞法:MD5被认为是不安全的,利用现有的MD5的强碰撞解题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//一些比较常用的MD5弱比较:
QNKCDZO
0e830400451993494058024219903391
240610708
0e462097431906509019562988736854
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
//MD5硬碰撞
a=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab
&b=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%5f%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%f3%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%e9%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%13%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%a8%1b%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%39%05%39%95%ab
&c=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%ed%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%a7%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%e6%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%16%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%33%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%6f%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab

在PHP中有些函数会在内部“使用”弱相等,比如switch()、in_array()等函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//switch()函数
<?php

$a='2abc';
switch($a){
case 1: //这里是弱比较
echo 1;
case 2: //同上
echo 2;
}
?> //结果会输出2

//intval()函数:将传入的参数转换为整数。如果参数是一个字符串,它会尝试将字符串中的数字部分提取出来并转换为整数。如果参数是浮点数,它会将浮点数截断为整数。如果参数是其他类型的值,它会尝试将其转换为整数。**这个漏洞已经被修复了,用未修复前的版本举个栗子**
//它不能用于 object,否则会产生 E_NOTICE 错误并返回 1(注意这个通常配合preg_match来使用)
<?php
$num=2e4;
echo $num; //20000

$b = intval($num);//2
if($b<2020 && intval($num+1)>2021){//让一个变量intval后小于2020但是加一在intval会大于2021,2e4就是一个理想的值

echo'hello world!';

}
?> //输出hello world!
//同理还可以用0x开头的十六进制、0开头的八进制进行一些绕过

//is_numeric() 函数的作用是判断给定的值是否为数字或数字字符串。如果值是数字或可以解析为数字的字符串,则返回 true;否则返回 false。
<?php

var_dump(is_numeric(123));//true
var_dump(is_numeric('123')); //true
var_dump(is_numeric('123.0')); //true
var_dump(is_numeric(0x776179));//true
var_dump(is_numeric('0x776179'));//flase
var_dump(is_numeric('123a'));//flase
var_dump(is_numeric('123 '));//flase

?>
//in_array()函数:用于检查一个值是否存在于数组中。
in_array($value, $array, $strict)
参数说明:

$value:要检查的值。
$array:要搜索的数组。
$strict(可选):指定是否进行严格的类型检查,默认为 false。如果设置为 true,则不仅要比较值,还要比较数据类型。

该函数会遍历数组中的每个元素,并与要检查的值进行比较。如果找到匹配的值,则返回 true,否则返回 false
问题出在$strict参数,弱不设置则为弱比较,绕过方法见上。

还在师傅们的文章上看到这么一个东西:preg_match与intval配合使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//preg_match只能处理字符串,如果不按规定传一个字符串,通常是传一个数组进去,这样就会报错
<?PHP
$flag = 'oh you find me!'
if(isset($_GET['num'])){

$num = $_GET['num'];

if(preg_match("/[0-9]/", $num)){

die("no no no!");

}

if(intval($num)){

echo $flag;

}

}
?>
//?num[]=1,传个数组可以绕过die,然后Intval数组会报错返回1,从而echo flag。

类似的还有array_search()函数:用于在数组中搜索指定的值,并返回该值对应的键(即数组中的索引位置)。语法如下

1
2
3
4
5
6
7
8
array_search($value, $array, $strict)
/*
$value:要搜索的值。
$array:要搜索的数组。
$strict(可选):指定是否进行严格的类型检查,默认为 false。如果设置为 true,则不仅要比较值,还要比较数据类型。

该函数会遍历数组中的每个元素,并与要搜索的值进行比较。如果找到匹配的值,则返回该值对应的键;如果找不到匹配的值,则返回 false。
*/

​ 这个函数的例题可以参考攻防世界中的easyphp。

参考了这些师傅们的文章,感谢:

1
2
3
https://blog.csdn.net/qq_47804678/article/details/128814377
https://blog.csdn.net/m0_48108919/article/details/123279251
https://www.jianshu.com/p/c53f7af34ee2

PHP中的弱相等和强相等
http://example.com/2023/09/11/[一些总结]php中的弱相等和强相等/
作者
notbad3
发布于
2023年9月11日
许可协议