Php 如何取消基本类型和数组的序列化?
我必须在我的项目中对用户提供的数据使用unserialize。 IFAIK对不可信数据使用unserialize是不安全的,因为可能通过隐式调用唤醒函数和析构函数()来执行用户代码 好的,我试过这样的smthPhp 如何取消基本类型和数组的序列化?,php,security,serialization,Php,Security,Serialization,我必须在我的项目中对用户提供的数据使用unserialize。 IFAIK对不可信数据使用unserialize是不安全的,因为可能通过隐式调用唤醒函数和析构函数()来执行用户代码 好的,我试过这样的smth $a = serialize(array('a'=>'b', 'c'=>20)); unserialize($a, array('allowed_classes'=>false)); 但unserialize会以这种方式忽略所有数据 因此,问题是: 如何取消序列化包含数
$a = serialize(array('a'=>'b', 'c'=>20));
unserialize($a, array('allowed_classes'=>false));
但unserialize会以这种方式忽略所有数据
因此,问题是:
如何取消序列化包含数组和基本数据类型(如int、string、bools等)的字符串,但不让自己取消序列化不需要的类的对象(并执行不需要的代码)
提前感谢。您没有提到您使用的是哪个版本的PHP,但是
unserialize
的第二个参数仅在PHP7中可用
发件人:
7.0.0已添加选项参数
PHP 5.5.9-1ubuntu4.20(cli):
PHP 7.0.12(cli):
带有序列化对象的PHP 7.0.12(cli):
php > $a = serialize(array('a'=>'b', 'c'=>20, 'd'=> new Exception));
php > var_dump(unserialize($a, array('allowed_classes'=>false)));
array(3) {
["a"]=>
string(1) "b"
["c"]=>
int(20)
["d"]=>
object(__PHP_Incomplete_Class)#1 (8) {
["__PHP_Incomplete_Class_Name"]=>
string(9) "Exception"
["message":protected]=>
string(0) ""
["string":"Exception":private]=>
string(0) ""
["code":protected]=>
int(0)
["file":protected]=>
string(14) "php shell code"
["line":protected]=>
int(1)
["trace":"Exception":private]=>
array(0) {
}
["previous":"Exception":private]=>
NULL
}
}
我不能保证它的安全性或完整性,但在unserialize
php文档中,使用>php 5.3的options参数给出了unserialize
的实现:
function php7_unserialize($str, $options = array())
{
if(version_compare(PHP_VERSION, '7.0.0', '>='))
{ return unserialize($str, $options); }
$allowed_classes = isset($options['allowed_classes']) ?
$options['allowed_classes'] : true;
if(is_array($allowed_classes) || !$allowed_classes)
{
$str = preg_replace_callback(
'/(?=^|:)(O|C):\d+:"([^"]*)":(\d+):{/',
function($matches) use ($allowed_classes)
{
if(is_array($allowed_classes) &&
in_array($matches[2], $allowed_classes))
{ return $matches[0]; }
else
{
return $matches[1].':22:"__PHP_Incomplete_Class":'.
($matches[3] + 1).
':{s:27:"__PHP_Incomplete_Class_Name";'.
serialize($matches[2]);
}
},
$str
);
}
unset($allowed_classes);
return unserialize($str);
}
是的,使用@unserialize是我的错误,因此我无法在PHP5.3中看到此警告。感谢php7_unserialize实现,就我所知,它看起来很安全。
php > $a = serialize(array('a'=>'b', 'c'=>20, 'd'=> new Exception));
php > var_dump(unserialize($a, array('allowed_classes'=>false)));
array(3) {
["a"]=>
string(1) "b"
["c"]=>
int(20)
["d"]=>
object(__PHP_Incomplete_Class)#1 (8) {
["__PHP_Incomplete_Class_Name"]=>
string(9) "Exception"
["message":protected]=>
string(0) ""
["string":"Exception":private]=>
string(0) ""
["code":protected]=>
int(0)
["file":protected]=>
string(14) "php shell code"
["line":protected]=>
int(1)
["trace":"Exception":private]=>
array(0) {
}
["previous":"Exception":private]=>
NULL
}
}
function php7_unserialize($str, $options = array())
{
if(version_compare(PHP_VERSION, '7.0.0', '>='))
{ return unserialize($str, $options); }
$allowed_classes = isset($options['allowed_classes']) ?
$options['allowed_classes'] : true;
if(is_array($allowed_classes) || !$allowed_classes)
{
$str = preg_replace_callback(
'/(?=^|:)(O|C):\d+:"([^"]*)":(\d+):{/',
function($matches) use ($allowed_classes)
{
if(is_array($allowed_classes) &&
in_array($matches[2], $allowed_classes))
{ return $matches[0]; }
else
{
return $matches[1].':22:"__PHP_Incomplete_Class":'.
($matches[3] + 1).
':{s:27:"__PHP_Incomplete_Class_Name";'.
serialize($matches[2]);
}
},
$str
);
}
unset($allowed_classes);
return unserialize($str);
}