最近Webのセキュリティについて勉強しているのだが、これまで常識的に使ってきた正規表現の「^$」を使うべきではないことが分かった。

まずは以下の例を見てみよう。

$param = filter_input(INPUT_GET, 'param');

if(!preg_match('/^[0-9]{1, 3}$/u', $param)) {
  echo '1〜3文字の半角数字を入力してください';
  return;
}

echo 'アクセス成功!';

このPHPファイルに対し、以下のURLでリクエストを送ったとする。

hoge.com/?param=12%0A

パラメータに付与した「%0A」はラインフィード(改行文字)を表すものだが、この場合preg_matchで指定した条件をすり抜けることができるのだ。

なぜこのようなことが起きたかというと、正規表現の「^」「$」はそれぞれ行頭・行末を表す記号で、「$」が改行にマッチすることから、データの終わりとして使ってしまうと不具合が生じる可能性があるというわけだ。

データの先頭・末尾を表す場合は、「\A」「\z」を使用するのが正しい書き方。

$param = filter_input(INPUT_GET, 'param');

if(!preg_match('/\A[0-9]{1, 3}\z/u', $param)) {
  echo '1〜3文字の半角数字を入力してください';
  return;
}

echo 'アクセス成功!';

先ほどのコードを書き直してみた。

今度は改行文字を含んだパラメータが投げられても、条件にマッチせずアクセスを弾くことができる。