第二十天 PHP弱类型安全问题总结

php
比较表 https://www.php.net/manual/zh/types.comparisons.php

PHP弱类型简介

在PHP中,可以进行一下的操作。

$a= 1;
$a = array();
$a = "stringg";

弱类型的语言对变量的数据类型没有限制,你可以在任何地时候将变量赋值给任意的其他类型的变量,同时变量也可以转换成任意地其他类型的数据。

类型转换问题

类型转换是无法避免的问题。例如需要将GET或者是POST的参数转换为int类型,或者是两个变量不匹配的时候,PHP会自动地进行变量转换。但是PHP是一个弱类型的语言,导致在进行类型转换的时候会存在很多意想不到的问题。

比较操作符

这里用到了PHP弱类型的一个特性,当一个整形和一个其他类型行比较的时候,会先把其他类型转换成整型再比。

使用比较操作符的时候也存在类型转换的问题,如下:

<?php
$a = '0';
$b = '';
$c = ' ';
$d = null;
$e = 0;
var_dump($a == $b);  //false
var_dump($a == $c);  //false
var_dump($a == $d);  //false
var_dump($a == $e);  //true
var_dump($b == $c);  //false
var_dump($b == $d);  //true
var_dump($b == $e);  //true
var_dump($c == $d);  //false
var_dump($c == $e);  //true
var_dump($d == $e); 

当不同类型的变量进行比较的时候就会存在变量转换的问题,在转换之后就有可能会存在问题。
在这里插入图片描述

自动类型转换为0了

当一个数字与字符串进行比较时 此时会发生字符串自动向数据类型的转换 从字符串左边开始到右边 如果取到数字 则接着往下取

否则结束

在这里插入图片描述
在这里插入图片描述
1、== :会先进行类型转换,再进行对比
2、===:会先比较类型,如果类型不同直接返回false,参考如下
https://www.php.net/manual/zh/types.comparisons.php

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十六进制转换

还存在一种十六进制余字符串进行比较运算时的问题。例子如下:

"0x1e240"=="123456"		//true
"0x1e240"==123456		//true
"0x1e240"=="1e240"		//false

当其中的一个字符串是0x开头的时候,PHP会将此字符串解析成为十进制然后再进行比较,0x1240解析成为十进制就是123456,所以与int类型和string类型的123456比较都是相等。phpy的这个特性。

在进行比较运算时,如果遇到了0x这类字符串,PHP会将它解析为十六进制

10进制数字和10进制数字认为都属于同一个整形的数据类型
在这里插入图片描述
变一下一个字符串现在是什么

在这里插入图片描述

类型转换
常见的转换主要就是int转换为string,string转换为int。 int转string:

$var = 5;
方式1$item = (string)$var;  
方式2$item = strval($var);

string转int:intval()函数。 对于这个函数,可以先看2个例子。

var_dump(intval('2'))        //2
var_dump(intval('3abcd'))    //3
var_dump(intval('abcd'))    //0

说明intval()转换的时候,会将从字符串的开始进行转换知道、、直到遇到一个非数字的字符。即使出现无法转换的字符串,intval()不会报错而是返回0。同时,程序员在编程的时候也不应该使用如下的这段代码:

if(intval($a)>1000) {
    
    
    mysql_query("select * from news where id=".$a)  //不要轻易比较
}
//这个时候$a的值有可能是1002 union…..

在5.6 及以下版本 此时当使用一个包含数字的字符串与一个16进制数字的字符串进行比较时 此时会进行一个默认的进制转换
7.2的话就不会默认转换
在这里插入图片描述

Hash比较 0exxxx

除了以上的这种方式之外在进行hash比较的时候也会存在问题。如下:

"0e132456789"=="0e7124511451155"   //true
"0e123456abc"=="0e1dddada"        //false
"0e1234"=="0"                    //true

在进行比较运算时,如果遇到了0e\d+这种字符串,就会将这种字符串解析为科学计数法。所以上面例子中2个数的值都是0因而就相等了。如果不满足0e\d+这种模式就不会相等。

php特性 当处理以0e开头的字符串的时候 相当于是一个0**1234567次方

5.6的版本
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

++$a $a-- 先加后减 区别

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

内置函数的参数的松散性

内置函数的松散性说的是,调用函数时给函数传递函数无法接受的参数类型。解释起来有点拗口,还是直接通过实际的例子来说明问题,

in_array() 函数

在PHP手册中,in_array()函数的解释是bool in_array ( mixed $needle , array $haystack [, bool s t r i c t = F A L S E ] ) , 如 果 s t r i c t 参 数 没 有 提 供 , 那 么 i n a r r a y 就 会 使 用 松 散 比 较 来 判 断 strict = FALSE ] ),如果strict参数没有提供,那么in_array就会使用松散比较来判断 strict=FALSE]),strictinarray使needle是否在$haystack中。当strict的值为true时,in_array()会比较needls的类型和haystack中的类型是否相同。

在这里插入图片描述
在这里插入图片描述

$array=array(0,1,2,'3');
var_dump(in_array('abc', $array)); //true
var_dump(in_array('1bc', $array)); //true

可以看到上面的情况返回的都是true,因为 ‘abc’ 会转换为0,‘1bc’ 转换为1。array_search()与in_array()也是一样的问题。

in_array,array_search 弱类型比较
松散比较下,任何string都等于true:

// in_array('a', [true, 'b', 'c'])       // 返回bool(true),相当于数组里面有字符'a'
// array_search('a', [true, 'b', 'c'])   // 返回int(0),相当于找到了字符'a'
// array_search 会使用'ctf'和array中的每个值作比较,这里的比较也是弱比较,所以intval('ctf')==0.
if(is_array(@$a["a2"])){
    
    
        if(count($a["a2"])!==5 OR !is_array($a["a2"][0])) die("nope");
        $pos = array_search("ctf", $a["a2"]);
        $pos===false?die("nope"):NULL;
        foreach($a["a2"] as $key=>$val){
    
    
            $val==="ctf"?die("nope"):NULL;
        }
        $v2=1;
}

strcmp() 特性

strcmp()函数在PHP官方手册中的描述是int strcmp ( string $str1 , string $str2 ),需要给strcmp()传递2个string类型的参数。如果str1小于str2,返回-1,相等返回0,否则返回1。strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算,然后根据运算结果来决定返回值。
如果传入给出strcmp()的参数是数字呢?

$array=[1,2,3];
var_dump(strcmp($array,'123')); //null,在某种意义上null也就是相当于false。

在这里插入图片描述
在这里插入图片描述
strcmp(string1,string2):比较括号内的两个字符串string1和string2,当他们两个相等时,返回0;string1的大于string2时,返回>0;小于时返回<0。
在5.3及以后的php版本中,当strcmp()括号内是一个数组与字符串比较时,也会返回null。

switch()

如果switch是数字类型的case的判断时,switch会将其中的参数转换为int类型。如下:

$i ="2abc";
switch ($i) {
    
    
case 0:
case 1:
case 2:
    echo "i is less than 3 but not negative";
    break;
case 3:
    echo "i is 3";
}

这个时候程序输出的是i is less than 3 but not negative,是由于switch()函数将$i进行了类型转换,转换结果为2。

md5 哈希碰撞

PHP手册中的md5()函数的描述是string md5 ( string $str [, bool $raw_output = false ] ),md5()中的需要是一个string类型的参数。但是当你传递一个array时,md5()不会报错,只是会无法正确地求出array的md5值,这样就会导致任意2个array的md5值都会相等。

$array1[] = array(
    "foo" => "bar",
    "bar" => "foo",
);
$array2 = array("foo", "bar", "hello", "world");
var_dump(md5($array1)==var_dump($array2));       //true

在这里插入图片描述
利用数组特性
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

md5 哈希碰撞
可以看一下 https://blog.csdn.net/m0_43405474/article/details/123228885?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164847994116782092971598%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164847994116782092971598&biz_id=0&spm=1018.2226.3001.4187

ctfhub : md5 collision
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。

攻击者可以利用这一漏洞,通过输入一个经过哈希后以”0E”开头的字符串,即会被PHP解释为0,如果数据库中存在这种哈希值以”0E”开头的密码的话,他就可以以这个用户的身份登录进去,尽管并没有真正的密码。

$a = $_GET[2];
$b = $_GET[1];
if ($a != $b && md5($a) == md5($b)){
    
    
    echo 'success';
}
else{
    
    
    echo 'failed';
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

  1. in_array 默认使用基于弱类型的比较 将类型也要考虑进去的话 第三个设置为true
  2. strcmp 默认进行一个字符串的比较 如果说第一个字符串排在第二个字符串前 返回-1
    否则第一个字符串排在第二个字符串后 返回1
    相等返回0
    如果使用strcmp函数将一个数组与字符串进行比较 则返回null
    3.md5
    hash碰撞 特定的字符串 直接比较不相等 md5值 弱类型比较时相等
    数组 md5 数组返回null

例题

<?php
include "flag.php";
if (isset($_GET['message'])) {
    
    
    $message = json_decode($_GET['message']);
    if ($message->key == $flag) {
    
    
        echo 'ok';
    } else {
    
    
        echo 'fail';
    }
}

在这里插入图片描述
在这里插入图片描述
传参中 默认服务器都将传递的参数当作是一个字符串

<?php

if (!is_array($_GET['bihuo'])){
    
    
    die();
}
$bihuo = $_GET['bihuo'];
for($i = 0; $i < count($bihuo); ++$i){
    
    
    if($bihuo[$i] === 'bihuo.cn'){
    
    
        echo 'no';
        die();
    }
    $bihuo[$i] = intval($bihuo[$i]);
}
 
if (array_search('bihuo.cn', $bihuo) === 0){
    
    
    echo 'ok, you get it ';
}
else{
    
    
    echo 'no, you failed';
}

在这里插入图片描述

在总结

in_array  判断对应的值是否存在于对应的数组中 默认进行基于弱类型的比较 如果说想要基于类型的比较 此时需要设置第三个参数$strict 为true
strcmp 函数 默认用来对比两个字符串的排序问题 当第一个字符串应该排在第二个字符串前 则返回负数(-1) 当第一个字符串应该排在第二个字符串后 返回正数(1) 相等返回0
	当使用strcmp比较一个字符串与数组 此时返回值为null

md5 函数 默认是将一个字符串生成对应的md5值
1. hash碰撞 两个字符串 不相等 md5之后的值均以0e作为开头 此时进行一个基于弱类型的比较 则认为相等
2. 当使用md5 处理数组时 此时返回值为null

json_decode 函数 将一个字符串生成json格式的内容 引入整型
array_search 函数 在数组中搜索是否存在特定的value值 如果存在 则返回其对应的key的值 否则返回false 默认进行基于弱类型的比较
switch 比较时默认使用弱类型来比较

参考 https://blog.spoock.com/2016/06/25/weakly-typed-security/
https://github.com/JnuSimba/MiscSecNotes/blob/master/PHP%E5%AE%89%E5%85%A8/php%20%E5%BC%B1%E7%B1%BB%E5%9E%8B%E9%97%AE%E9%A2%98.md
https://www.ddosi.org/b174/#%E5%BC%B1%E7%B1%BB%E5%9E%8B%E6%AF%94%E8%BE%83

猜你喜欢

转载自blog.csdn.net/qq_42096378/article/details/123794432
今日推荐