最新のPHPニュース

preg_matchの注意点

2007年04月05日

PHP Security Blogpreg_matchをフィルターとして使用する際の注意点について言及されています。

以下のような$_GET['var']をフィルタリングするスクリプトを考えます。

<?php
$clean = array();
if (preg_match("/^[0-9]+:[X-Z]+$/", $_GET['var'])) {
 $clean['var'] = $_GET['var'];
}
?>

この場合、改行文字が$_GET['var']の最後にあってもpreg_matchはその改行文字を「$」で捉えることができません。

<?php
$str_list = array(
  "OK" => "1234:XYZ",
  "OK_EOL" => "1234:XYZ" . PHP_EOL,
  "NG_1" => "1234:XYZ" . PHP_EOL . "aaa"
);
 
foreach ($str_list as $k => $v) {
 if (preg_match("/^[0-9]+:[X-Z]+$/", $v)) {
   echo $k . " => " . $v;
   echo PHP_EOL . "----------------" . PHP_EOL;
 }
}
?>

上記のスクリプトの実行結果は以下のようになります。

OK => 1234:XYZ
----------------
OK_EOL => 1234:XYZ

----------------

preg_matchでは評価する文字列の最後が改行文字の場合、その文字列は評価されません。ただし、「D」修飾子を追加することでこの動作を修正することができます。

<?php
$str_list = array(
  "OK" => "1234:XYZ",
  "OK_EOL" => "1234:XYZ" . PHP_EOL,
  "NG_1" => "1234:XYZ" . PHP_EOL . "aaa"
);
 
foreach ($str_list as $k => $v) {
 if (preg_match("/^[0-9]+:[X-Z]+$/D", $v)) {
   echo $k . " => " . $v;
   echo PHP_EOL . "----------------" . PHP_EOL;
 }
}
?>
OK => 1234:XYZ
----------------

これは、HTTPヘッダインジェクションや、E-mailのヘッダーインジェクション攻撃の元となりうるので注意が必要です。ただし、HTTPヘッダインジェクション攻撃は、PHPのheader()関数で複数のヘッダをPHP 4.4.2およびPHP 5.1.2以降では出力できなくなっているので、最新のPHPではこのフィルターを通過した値をheader()関数で使用しても改行文字が他のヘッダに影響を与えることはありません。

いずれにしても、trim()関数などでの処理はヘッダに使用する値に関しては忘れてはいけないことなので、注意しましょう。

関連リンク

関連ニュース

この記事へのトラックバックURL