[PHP] preg_replace における //e があぶない話
Malware Hidden Inside JPG EXIF Headers という話題がでていたので見てみたところ、単に preg_replace がセキュリティ上問題があるインターフェイスだという話であって、EXIF 云々は直接的に 関係がなく、釣りエントリであることが判明した。
preg_replace は第一引数に正規表現を渡すが、その際に外部からの入力をそのままわたすと危険という話。 なぜならば preg_replace は '/.*/e' のように、eval flag をわたすことができるからだ。
以下のコードをみよ。
<?php
preg_replace('/.*/e', 'eval("echo 5960+3;")', '');
つまり、preg_replace($_POST['foo'], $_POST['bar'], '')
のようなコードがあった場合、任意のコードが実行可能となってしまう。
ただ、preg_replace における //e オプションは、PHP 5.5.0 で deprecated になっているので、しばらくしたら使えなくなるので世界は平安をとりもどすことだろう。
preg_replace のインターフェイスが、bad であることは言うまでもないが、また一方でユーザーの側に問題があることもまた言うまでもない。 任意のユーザー入力をそのまま正規表現としてうけとると、容易に DoS(Denial of Service) が可能となるということはよく知られている事実であるから、任意のユーザー文字列を正規表現としてうけとっている時点で脆弱なサーバー実装になっている。
基本的に、任意のユーザー入力を正規表現として評価することはさけなければなりません。