データの状態
バリデーションの観点から言うと、データには状態が2つ存在する。
1つは汚染されている状態、もう1つは除染された状態。
この2つの状態はデータの内容が変わるので、検証方法も変わる。
汚染データ検証
$num = $_POST['num'];
// $num は汚染データ
$_POSTから取ったばかりのデータは汚染されているデータである。
不潔、汚い、醜い、きらい。
そんなデータである。
これを検証する。
$result = filter_var($num, FILTER_VALIDATE_INT);
if ($result === false) {
die("invalid num");
}
$num = $result;
filter_var
関数は第1引数を第2引数の指定で検証する。上記ではnumをintにしている。
numが不正な値だったらfalseが返る。
この時点の検証は「汚染データの検証」である。
つまり、データは汚染されている。汚染されているのだ。
汚染データが不正だということは、入力が不正だということである。
入力がおかしいということは、攻撃やバグの可能性がある。
つまりアタッカーの攻撃は、汚染データ検証で検出することができる。
除染データ検証
さきほどはfilter_var
でデータを除染した。
filter_var
によってnumはintになった。
ここからは除染データの検証である。
if ($num < 0 || $num >= 100) {
die("invalid num range");
}
numが指定範囲の整数かどうかチェックする。
numは整数なのでシステムにとっては無害なものであるが、値の大きさによっては害があるものに変わることもありえる。
そのため、ここで検証する必要がある。
値が範囲外の大きさであればこれも攻撃か、あるいはバグである可能性が高い。
つまり汚染状態のデータでも攻撃を検知できるし、除染後のデータでも攻撃を検知できるということになる。
汚染データと除染データでそれぞれ検証を設けることで、二重に攻撃を検知することができる。
サニタイズ
汚染データが不正である場合、攻撃かバグの可能性が高いということだが・・・。
汚染データの検証を入れずにデータをサニタイズすると、この攻撃を検知できなくなる。
// 以下のコードではmsgが攻撃データかどうか検知できない
$msg = $_POST['msg'];
$clean_msg = htmlspecialchars($msg);
echo $clean_msg;
よって、サニタイズ前に検証処理を入れることで攻撃を検知することができる。
// 汚染データ
$msg = $_POST['msg'];
// 汚染データ検証
if (has_html_tag($msg)) {
die("invalid msg");
}
// 除染
$clean_msg = htmlspecialchars($msg);
// 除染データ検証
if (strlen($clean_msg) >= MAX_MSG_LEN) {
die("invalid msg len");
}
// 出力
echo $clean_msg;
汚染と除染
検証におけるデータの状態は
- 汚染
- 除染(済み)
の2つ。
これを頭に入れておくとコードが捗る(はず)。
ぴよぴよぴ~!