LoginSignup
0
0

More than 3 years have passed since last update.

PHPのunserialize関数に脆弱性を生む可能性あり。配列をテキスト化しその逆を行うクラスを作成し対応しました。

Last updated at Posted at 2019-08-17

unserialize関数に脆弱性を生む可能性あり。その対策を検討する。

配列をシリアル化する方法として、serialize関数、復元するのにunserialize関数を使っていた方多いのではないでしょうか?
しかし、unserialize関数には脆弱性を生む可能性があり、使用は避けるべきであることが知られています。

参考)徳丸浩の日記
PHPのunserialize関数に外部由来の値を処理させると脆弱性の原因になる

徳丸先生によると、下記の関数を使い、シリアライズ化するべきであると主張されてます。

  • json_encode/json_decodeを使用する方法
  • implode/explodeを使用する方法

json_encode/json_decodeを使用する方法ですが、"が含まれている場合などには勝手にエスケープされ、json_decodeで元に戻せなくなるのでこの方法は却下しました。
そこで、この記事では配列化するモジュールを作成することで対応する方法を紹介します。

シリアライズクラス(sクラス)

このクラスは多次元配列や連想配列、またその組み合わせにも対応しております。

class s{
    public static $talkens=array("ooo--keyvalue%s--ooo","\nooo--line%s--ooo\n");
    public static function en($v,$i=0){
        if(!$v)return '';
        if(!is_array($v))return $v;
        $talkens= array(sprintf(self::$talkens[0],$i),sprintf(self::$talkens[1],$i));
        $ret    = array();
        foreach($v as $k => $tmp){
            if(is_array($tmp)){
                $tmp = self::en($tmp,($i+1));
            }
            $ret[]=implode($talkens[0],array($k,$tmp));
        }
        return implode($talkens[1],$ret);
    }
    public static function de($v,$i=0){
        if(!$v)return '';
        $talkens     = array(sprintf(self::$talkens[0],$i    ),sprintf(self::$talkens[1],$i    ));
        $talkens_next= array(sprintf(self::$talkens[0],($i+1)),sprintf(self::$talkens[1],($i+1)));
        $ret         = array();
        $tmp         = explode($talkens[1],$v);
        if($tmp){
            foreach($tmp as $tmp_){
                $ar = explode($talkens[0],$tmp_);
                $val= $ar[1];
                if(strpos($val,$talkens_next[0]) !== false){
                    $val = self::de($val,($i+1));
                }
                $ret[$ar[0]]=$val;
            }
        }
        return $ret;
    }
}

クライアントコード

$v=array(
    '9'=>array('福岡'),
    array(33=>'大阪','宮崎'),
    't'=>array('東京','神奈川')
);
var_dump($v);
$v = s::en($v);
var_dump($v);
$v = s::de($v);
var_dump($v);

上記コードを実行すると下記になります。

シリアライズ前
array(3) {
  [9]=>
  array(1) {
    [0]=>
    string(6) "福岡"
  }
  [10]=>
  array(2) {
    [33]=>
    string(6) "大阪"
    [34]=>
    string(8) "宮崎"
  }
  ["t"]=>
  array(2) {
    [0]=>
    string(6) "東京"
    [1]=>
    string(9) "神奈川"
  }
}
シリアライズ後
string(266) "9ooo--keyvalue0--ooo0ooo--keyvalue1--ooo福岡
ooo--line0--ooo
10ooo--keyvalue0--ooo33ooo--keyvalue1--ooo大阪
ooo--line1--ooo
34ooo--keyvalue1--ooo宮崎
ooo--line0--ooo
tooo--keyvalue0--ooo0ooo--keyvalue1--ooo東京
ooo--line1--ooo
1ooo--keyvalue1--ooo神奈川"
復元後
array(3) {
  [9]=>
  array(1) {
    [0]=>
    string(6) "福岡"
  }
  [10]=>
  array(2) {
    [33]=>
    string(6) "大阪"
    [34]=>
    string(8) "宮崎"
  }
  ["t"]=>
  array(2) {
    [0]=>
    string(6) "東京"
    [1]=>
    string(9) "神奈川"
  }
}

オフィスアンツ

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0