PHP弱类型安全
PHP弱类型安全
PHP弱类型简介
强类型是两个不同类型的变量不能用同一块内存存储
弱类型是两个不同类型的变量可以用同一块内存存储
PHP是弱类型语言
类型转换问题
=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较
== 在进行比较的时候,会先将字符串类型转化成相同,再比较
hash比较缺陷
"0e132456789"=="0e7124511451155" //true
"0e123456abc"=="0e1dddada" //false
"0e1abc"=="0" //false
"2e1"=="20" //true
以下值在md5加密后以0E开头:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
S214587387a
以下值在sha1加密后以0E开头:
sha1(‘aaroZmOk’)
sha1(‘aaK1STfY’)
sha1(‘aaO8zKZF’)
sha1(‘aa3OFF9m’)
在进行比较运算时,如果遇到了0ed+这种字符串,就会将这种字符串解析为科学计数法。如果不满足0ed+这种模式,就会当作字符串进行比较,所以不会相等。
十六进制转换
"0x1e240"=="123456" //true
"0x1e240"==123456 //true
"0x1e240"=="1e240" //false
当其中的一个字符串是0x开头的时候,PHP会将此字符串解析成为十进制然后再进行比较。
类型转换
<?php
$test=1 + "10.5"; // $test=11.5(float)
$test=1+"-1.3e3"; //$test=-1299(float)
$test=1+"bob-1.3e3";//$test=1(int)
$test=1+"2admin";//$test=3(int)
$test=1+"admin2";//$test=1(int)
?>
PHP手册:当一个字符串欸当作一个数值来取值,其结果和类型如下:如果该字符串没有包含'.','e','E'
并且其数值值在整形的范围之内该字符串被当作int来取值,其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。
intval()函数:获取变量的整数值,intval()转换的时候,会将从字符串的开始进行转换知道遇到一个非数字的字符。即使出现无法转换的字符串,intval()不会报错而是返回0。
<?php
var_dump(intval('2')); //2
var_dump(intval('3abcd')); //3
var_dump(intval('ab4cd345')); //0
?>
bool欺骗
当存在json_decode和unserialize的时候,部分结构会被解释成bool类型。
json_decode示例代码:
<?php
$json_str = '{"user":true,"pass":true}';
$data = json_decode($json_str,true);
if ($data['user'] == 'admin' && $data['pass']=='secirity')
{
print_r('logined in as bool'."\n");
}
?>
logined in as bool
unserialize示例代码:
$unserialize_str = 'a:2:{s:4:"user";b:1;s:4:"pass";b:1;}';
$data_unserialize = unserialize($unserialize_str);
var_dump($data_unserialize['user']);
if ($data_unserialize['user'] == 'admin' && $data_unserialize['pass']=='secirity')
{
print_r('logined in unserialize'."\n");
}
bool(true)
logined in unserialize
数字转换问题
<?php
var_dump("1" == 0.9999999999999999);//false
var_dump("1" == 0.99999999999999999);//true
?>
int和intval在转换数字的时候都是向下取整
<?php
var_dump((int)'0.9999999999999');//0
var_dump((int)'1.1');//1
?>
intval还有个尽力模式,就是转换所有数字直到遇到非数字为止,如果采用:
if (intval($qq) === '123456')
{
$db->query("select * from user where qq = $qq")
}
可以传入123456 union select version()
进行注入。
php5.4.4特殊情况
这个版本的php的一个修改导致两个数字型字符溢出导致比较相等
$ php -r 'var_dump("61529519452809720693702583126814" == "61529519452809720000000000000000");'
bool(true)
MD5
<?php
$array1[] = array("foo" => "bar", "bar" => "foo",);
$array2 = array("foo", "bar", "hello", "world");
print_r($array1);
echo "<br>";
var_dump(md5($array1)==md5($array2)); //true
?>
PHP手册中的md5()函数的描述是string md5 ( string $str [, bool $raw_output = false ] )
,md5()中的需要是一个string类型的参数。但是当你传递一个array时,md5()不会报错,只是会无法正确地求出array的md5值,并且返回NULL
。这样就会导致任意2个array的md5值都会相等。
md5('ffifdyop',true); 可以用于sql注入
<?php
var_dump(md5('ffifdyop',true)); //true
?>
'or'6É]™é!r,ùíb
以下值在md5加密后以0E开头:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
S214587387a
以下值在sha1加密后以0E开头:
sha1(‘aaroZmOk’)
sha1(‘aaK1STfY’)
sha1(‘aaO8zKZF’)
sha1(‘aa3OFF9m’)
substr sha1
如果传入给substr(),sha1的参数是数组则返回NULL
<?php
$cc=[];
var_dump(substr($cc, 123));
var_dump(sha1($cc));
var_dump(substr($cc, 123) === sha1($cc));
?>
NULL
NULL
bool(true)
strcmp()
$array=[1,2,3];
var_dump(strcmp($array,'123')); //null,在某种意义上null也就是相当于false。
strcmp()函数在PHP官方手册中的描述是int strcmp ( string $str1 , string $str2 )
,需要给strcmp()传递2个string类型的参数。如果str1小于str2,返回-1,相等返回0,否则返回1。strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算,然后根据运算结果来决定返回值。
如果传入给出strcmp()的参数是数组则返回NULL
switch
如果switch是数字类型的case的判断时,switch会将其中的参数转换为int类型。如下:
<?php
$i ="2abc";
switch ($i) {
case 0:
case 1:
case 2:
echo "case 2";
break;
case 3:
echo "case 3";
}
?>
case 2
in_array()
$array=[0,1,2,'3'];
var_dump(in_array('abc', $array)); //true
var_dump(in_array('1bc', $array)); //true
’abc’
会转换为0,’1bc’
转换为1。array_search()与in_array()也是一样的问题。