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) "神奈川"
}
}