この記事は以下の書籍のアウトプットとして執筆しました。
Webアプリケーションの入力は何をするか
入力処理では入力値に対して以下の処理を行う
a. 文字エンコーディングの妥当性検証
→文字エンコーディングを使った攻撃対策ため
b. 文字エンコーディングの変換
→HTTPメッセージとプログラム内部でも自演コーディグが異なるため
c. 入力値の妥当性検証
→セキュリティ上の保険的な対策
文字エンコーディングの検証
PHPではmb_check_encoding関数が使える
文字エンコーディングの変換
PHPはphp.iniでの設定で自動変換と明示的な返還を選べる。
入力値検証
バイナリセーフとヌルバイト攻撃
バイナリセーフ
入力値がどんなバイト列であっても正しく扱えることを意味する。
典型亭には値ゼロのバイト(ヌルバイト、PHP言語では\0と表記)が現れても正しく処理することを指す。
ヌルバイトが特別扱いされるのはC言語及びUnixやウィンドウズのAPIでは、ヌルバイトを文字列の終端とみなす取り決めがある。
C言語で開発されたPHPは塗るバイトを文字列の終端としてそれ以降を切り詰める関数がある。
このような関数をバイナリセーフでない関数という。
eregの検査を回避
この関数は PHP 5.3.0 で 非推奨 となり、 PHP 7.0.0 で 削除 されました。
<body>
<?php
$p = $_GET['p'];
if (ereg('^[0-9]+$', $p) === FALSE) {
die('整数値を入力してください');
}
echo $p;
?>
</body>
このコードに対して以下のようにアクセスするとeregを回避される。
?p=1%00<script>alert('XSS')</script>
回避される理由
URLの中に%00
がある。これは値ゼロのバイトすなわちヌルバイトでereg関数はバイナリセーフの関数ではないため、塗るバイトがあるとそこで文字列が終わっていると判断してしまう。
ヌルバイト対策はバイナリセーフの関数のみを用いてアプリを開発すればいいが、それは困難
ファイル名のように仕様上ヌルバイトを許容しないパラメータがあるから。
このため、アプリの入り口で倍ナチセーフを使って入力値の塗るバイトをチェックして、塗るバイトがあればエラーにする方法がある
制御文字のチェック
制御文字とは改行やタブ等通常表示されない文字のことでヌルバイトも含まれる。
文字数のチェック
すべてのパラメータで最大文字数をチェックスべき。
これをチェックしておくとセキュリティ上で保険になる。
攻撃は文字列が長いことが多いため。
PHPの正規表現
入力値検証には正規表現が便利。
関数 | 説明 |
---|---|
perg | 文字エンコーディングがUTF-8の場合のみ日本語が使える |
mb_ereg | 様々な文字エンコーディングに使える |
1文字以上5文字以下の英数字をチェックする正規表現
preg_match('/A[a-z0-9]{1,5}\z/ui',$p);
名前 | 説明 |
---|---|
u修飾子 | UTF-8エンコーディングであることを示す。 |
i修飾子 | 大文字小文字を区別しない |
u修飾子は不要の場合があるが。正規表現の「.」なドアが意図しない結果になるため、常にu修飾子を指定しておくほうがいい
全体一致は\Aと\zで示す
データの先頭は\A
データの末尾は\z
で示す。
^
と$
は「行の」先頭と末尾を示すものだから$
は改行にマッチする。
このため^
と$
をデータの先頭・末尾として使うと不具合が生じる場合がある。