原标题:php弱类型问题总结 No.1 本文转载来自CSDN作者:耀答案 版权归原作者所有 原文链接:https://blog.csdn.net/weixin_42412194/article/details/115155140?spm=1001.2014.3001.5501
No.2 弱类型介绍 php是特别方便的一个语言,在申明一个变量的时候,并不需要指明它保存的数据类型,但是由于其自身弱类型语言的特性以及内置函数对于传入参数的松散处理,会带来很多的安全问题,这里将进行简要介绍。 弱类型语言对变量的数据类型没有限制,可以将变量赋值成其他类型变量,同时变量可以转换成任意其他类型的数据。 No.3 弱类型会产生的问题 使用PHP函数对变量$x进行比较: 编辑 ==比较两个变量的值,不比较数据类型。 编辑 ===比较两个变量的值和类型。 编辑 类型转换问题 类型转换是无法避免的问题。例如需要将GET或者是POST的参数转换为int类型,或者是两个变量不匹配的时候,PHP会自动地进行变量转换。但是PHP是一个弱类型的语言,导致在进行类型转换的时候会存在很多意想不到的问题。 var_dump("abc" == 0); //bool(true) var_dump("1ab" == 1); //bool(true) var_dump("ab1" == 1); //bool(false) var_dump("ab0" == 0); //bool(true) 1.int转string: $var = 5; 方式1:$item = (string)$var; 方式2:$item = strval($var); 2.string转int:intval()函数 var_dump(intval('2')) //2 var_dump(intval('3abcd')) //3 var_dump(intval('abcd')) //0 在intval()转换的时候,会将从字符串的开始进行转换知道遇到一个非数字的字符。即使出现无法转换的字符串,intval()不会报错而是返回0。 3.Hash比较 "0e132456789"=="0e7124511451155" //true "0e123456abc"=="0e1dddada" //false "0e1abc"=="0" //true 在进行比较运算时,如果遇到了0e\d+这种字符串,就会将这种字符串解析为科学计数法。所以上面例子中2个数的值都是0因而就相等了。如果不满足0e\d+这种模式就不会相等。 4.十六进制转换 "0x1e240"=="123456" //true "0x1e240"==123456 //true "0x1e240"=="1e240" //false 当其中的一个字符串是0x开头的时候,PHP会将此字符串解析成为十进制然后再进行比较,0x1240解析成为十进制就是123456,所以与int类型和string类型的123456比较都是相等。 5.函数松散性 switch 如果switch是数字类型的case的判断时,switch会将其中的参数转换为int类型。 $abc = "1ab"; switch ($abc) { case 1: echo "this is 1."; //输出 break; case 2: echo "this is 2."; break; case 3: echo "this is 3."; break; } $abc = "abc"; switch ($abc) { case 0: echo "this is 1."; //输出 break; case 1: echo "this is 2."; break; case 2: echo "this is 3."; break; } 这里再说一下switch函数没有break的情况,它会一直向下执行。 $abc = "abc"; switch ($abc) { case 0: echo "this is 1."; //输出 case 1: echo "this is 2."; //输出 case 2: echo "this is 3."; //输出 } md5 0e开头的全部相等(绕过==判断),两个字符串转换成MD5值时都是0e开头,0e 纯数字这种格式的字符串在判断相等的时候会被认为是科学计数法的数字,先做字符串到数字的转换。 var_dump(md5('240610708') == md5('QNKCDZO')); //bool(true) 纯数字类: 240610708 0e462097431906509019562988736854 314282422 0e990995504821699494520356953734 571579406 0e972379832854295224118025748221 903251147 0e174510503823932942361353209384 1110242161 0e435874558488625891324861198103 1320830526 0e912095958985483346995414060832 1586264293 0e622743671155995737639662718498 2302756269 0e250566888497473798724426794462 2427435592 0e067696952328669732475498472343 2653531602 0e877487522341544758028810610885 3293867441 0e471001201303602543921144570260 3295421201 0e703870333002232681239618856220 3465814713 0e258631645650999664521705537122 3524854780 0e507419062489887827087815735195 3908336290 0e807624498959190415881248245271 4011627063 0e485805687034439905938362701775 4775635065 0e998212089946640967599450361168 4790555361 0e643442214660994430134492464512 5432453531 0e512318699085881630861890526097 5579679820 0e877622011730221803461740184915 5585393579 0e664357355382305805992765337023 6376552501 0e165886706997482187870215578015 7124129977 0e500007361044747804682122060876 7197546197 0e915188576072469101457315675502 7656486157 0e451569119711843337267091732412 大写字母类: QLTHNDT 0e405967825401955372549139051580 QNKCDZO 0e830400451993494058024219903391 EEIZDOI 0e782601363539291779881938479162 TUFEPMC 0e839407194569345277863905212547 UTIPEZQ 0e382098788231234954670291303879 UYXFLOI 0e552539585246568817348686838809 IHKFRNS 0e256160682445802696926137988570 PJNPDWY 0e291529052894702774557631701704 ABJIHVY 0e755264355178451322893275696586 DQWRASX 0e742373665639232907775599582643 DYAXWCA 0e424759758842488633464374063001 GEGHBXL 0e248776895502908863709684713578 GGHMVOE 0e362766013028313274586933780773 GZECLQZ 0e537612333747236407713628225676 NWWKITQ 0e763082070976038347657360817689 NOOPCJF 0e818888003657176127862245791911 MAUXXQC 0e478478466848439040434801845361 MMHUWUV 0e701732711630150438129209816536 md5()中的需要是一个string类型的参数。但是当你传递一个array时,md5()`不会报错,只是会无法正确地求出array的md5值,返回false,这样就会导致任意2个array的md5值都会相等。(绕过===判断) $array1=array(1,2,3); $array2=array(4,5,6); var_dump(md5($array1)===md5($array2)) //true sha1 sha1函数和md5函数一样不能判断数组的值。 $array1=[1,2,3]; $array2=[4,5,6]; var_dump(sha1($array1)===sha1($array2)); //true strcmp strcmp()函数在PHP官方手册中的描述是int strcmp ( string $str1 , string $str2 ) ,需要给strcmp()传递2个string类型的参数。如果str1小于str2,返回-1,相等返回0,否则返回1。strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算,然后根据运算结果来决定返回值。 $array=[1,2,3]; var_dump(strcmp($array,'123')); //null,如果是==比较的话,null就等于false josn(这个不符合松散性) json_decode()对 JSON 格式的字符串进行解码 if (isset($_POST['message'])) { $message = json_decode($_POST['message']); $key ="*********"; if ($message->key == $key) { echo "flag"; } else { echo "fail"; } } else{ echo "~~~~"; } ?> 输入一个json类型的字符串,json_decode函数解密成一个数组,判断数组中key的值是否等于 $key的值,但是$key的值我们不知道,但是可以利用0和字符串==比较相等绕过。 6.最终payload为:message={"key":0} in_array/array_search 在PHP手册中,in_array()函数的解释是bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ) ,如果strict参数没有提供,那么in_array就会使用松散比较来判断$needle是否在$haystack中。当strince的值为true时,in_array()会比较needls的类型和haystack中的类型是否相同。 $array=[0,1,2,'3']; var_dump(in_array('abc', $array)); //true var_dump(in_array('1bc', $array)); //true 可以看到上面的情况返回的都是true,因为'abc'会转换为0,'1bc'转换为1。 is_numeric is_numeric() 函数用于检测变量是否为数字或数字字符串。在这里我们的payload需要是一个大于1336的数字后面加上非数字即可(%00也可以),如1337+,他不是数字或数字字符串,但是与数字1336进行比较时,又会把前面的1337当成数字来运算。 error_reporting(0); $flag = "flag{test}"; $temp = $_GET['password']; is_numeric($temp)?die("no numeric"):NULL; if($temp>1336){ echo $flag; } ?> intval Intval()函数最大的值取决于操作系统。32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。 一个数值超出限制的话依然会返回最大值 echo intval('9223372036854775807000'); //输出2147483647 No.4 总结 弱类型确实提升了程序员书写代码的效率,但是也带来了严重的安全问题。在使用PHP的比较时,注意合理利用松散比较与严格比较的区别和规范传入的参数类型,防止漏洞的出现。
|