2016-11-03 3 views
0

Мне нужно использовать unserialize с предоставленными пользователем данными в моем проекте. IFAIK, используя unserialize с ненадежными данными, небезопасен из-за возможности выполнить код пользователя через неявный вызов функции пробуждения и деструктора (https://wiki.php.net/rfc/secure_unserialize).Как можно безопасно выполнить кеширование базовых типов и массивов?

КИ, я пытался что-л, как этот

$a = serialize(array('a'=>'b', 'c'=>20)); 
unserialize($a, array('allowed_classes'=>false)); 

но десериализация игнорирует все данные, которые таким образом ...

Итак, вопрос: как я могу десериализируется строка содержит массив (s) и базовые типы данных (например, ints, strings, bools и т. д.), но защитите себя от несериализации объектов нежелательных классов (и выполните нежелательный код)?

Заранее спасибо.

ответ

2

Вы не упомянули, какую версию PHP вы используете, но второй аргумент unserialize доступен только в PHP 7.

От php.net:

7.0.0 Параметр опции было добавлено.

РНР 5.5.9-1ubuntu4.20 (CLI):

php > $a = serialize(array('a'=>'b', 'c'=>20)); 
php > var_dump(unserialize($a, array('allowed_classes'=>false))); 
PHP Warning: unserialize() expects exactly 1 parameter, 2 given in php shell code on line 1 
PHP Stack trace: 
PHP 1. {main}() php shell code:0 
PHP 2. unserialize() php shell code:1 
bool(false) 

PHP 7.0.12 (CLI):

php > $a = serialize(array('a'=>'b', 'c'=>20)); 
php > var_dump(unserialize($a, array('allowed_classes'=>false))); 
array(2) { 
    ["a"]=> 
    string(1) "b" 
    ["c"]=> 
    int(20) 
} 

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 
    } 
} 

Я не могу говорить за это безопасность или полнота, но comment 119851 в в unserialize PHP Документах это implmentation из unserialize с аргументом опции для> PHP 5.3:

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); 
} 
+0

да, это была моя ошибка использовать @unserialize, так что я не был в состоянии видеть это предупреждение с PHP 5.3. – AlexandrX

+0

и спасибо за реализацию php7_unserialize, он выглядит безопасным, насколько я могу судить. – AlexandrX

Смежные вопросы