CakePHPのセキュリティホール(まだの方はご対応を!)から、unserialize()が話題になっています。
このセキュリティホールは、外部から送信された値をチェックせずにunserialize()したことが引き金になっており、安全でない値をunserialize()することの危険性が指摘されています。
下記エントリでは、コードを交えてunserialize()から__destruct()が実行される過程が解説されています。
PHP5 __destruct() and unserialize() function – TokuLog 改メ tokuhirom’s blog
念のための補足なのですが、unserialize()から__destruct()が呼ばれるわけではありません。
下記コードは、PHP5.3.3で実行しています。
unserialize()から実行される関数
unserialize()から実行される関数(メソッド)は以下です。
__autoload、spl_autoload*などのオートローダー
デシリアライズするインスタンスのクラス定義を探す時に実行される可能性があります。
unserialize_callback_funcで設定した関数
上記オートローダー実行してもデシリアライズするインスタンスのクラス定義が存在しない場合に実行されます。ini_set()等で設定していなければ実行されません。
__wakeup
デシリアライズしたインスタンスに__wakeupメソッドが定義されていれば実行されます。
unserialize()から間接的に実行される関数
デシリアライズしたインスタンスの操作によって、結果実行される可能性があるのは以下です。
__destruct()
デシリアライズしたインスタンスの参照が0になったタイミングで実行されます。通常必ず実行されます。
__toString() / __set() / __get() / __call() / __invoke()などのマジックメソッド
デシリアライズしたインスタンスへの操作によって実行される可能性があります。
この中で実行されそうなのは__toString()です。unserialize()した値が文字列だと想定して以下のようなコードを書いていると__toString()が実行されます。
func start Foo::__toString func end
unserialize()で__destruct()が実行される?
上記でも触れたように__destruct()は、unserialize()で呼ばれるわけではなく、デシリアライズしたインスタンスの参照が0になるタイミングで実行されます。
これは通常のクラスインスタンスと同じ挙動です。
下記コードを実行してみるとその挙動が確認できます。
実行結果
% php unserialize.php func start func end Foo::__destruct <--- "func end"の後
ただ以下のようにunserialize()の戻り値を変数に格納しない場合は、デシリアライズしたインスタンスへの参照がありませんので、即時に__destruct()が実行されます。
func start Foo::__destruct // unserialize()して、即__destruct()が呼ばれる func end
[おまけ] protected/privateな変数もデシリアライズ可能
ちなみにunserialize()では、protected/privateなインスタンス変数もデシリアライズ可能です。インスタンス変数をprotected/privateにしたところで、unserialize()で汚染される可能性があることには変わりありません。
object(Foo)#2 (3) { ["var1"]=> string(6) "public" ["var2":protected]=> string(9) "protected" ["var3":"Foo":private]=> string(7) "private" }
でも結果としては実行される
unserialize()が__destruct()を直接実行するわけではないですが、デシリアライズしたインスタンスはどこかで破棄されるので、結果として__destruct()が実行されることには変わりありません。
ただやみくもに「unserialize()が__destruct()を実行する」と考えると問題を見誤る可能性があるのでご注意を。
参考リンク
- Newer: PHP シリアライズデータ型(PHP Advent Calendar jp 2010 Day 2)
- Older: CakePHPのSecurityComponentに深刻なセキュリティホールが見つかりました
トラックバック:0
- このエントリーのトラックバックURL
- /blog/2010/11/php_unserialize_do_not_call_destruct.html/trackback
- Listed below are links to weblogs that reference
- PHP unserialize()が__destruct()を実行する? from Shin x blog