第6章 入力・注入対策
入力対策

「入力対策」の基本は入力を受け取る箇所を特定し、正しく処理できる入力だけを受け取る様にすることである。想定外の動きにならない為に、どれだけの長さまたは大きさのものまで取り扱うのか、どのような型のデータとして取り扱うのかなどの仕様を明確にし、できるだけ限定するようにしなければならない。

入力検査漏れ

Webアプリケーションに入力検査漏れがあれば、そこからWebサイトや正規ユーザが攻撃され得る。入力検査漏れには概ね次の 3つのパターンがある。

  1. 入力検査において全項目が網羅されていない
  2. クライアント側スクリプトの検査ロジックが迂回される
  3. 数値範囲検査において攻撃を見逃す

1. 入力検査において全項目が網羅されていない

Webアプリケーションには、ユーザはキー入力をしないがプログラムはブラウザから値を受け取るというデータ項目がある。例えば、次のような項目である。

フォーム項目(主なもの)
  1. チェックボックス
  2. ラジオボタン
  3. <select> - <option>タグによる選択項目
  4. 不可視項目
  5. ボタン類
HTTPリクエストヘッダ項目(主なもの)
  1. Cookie:
  2. Referer:
  3. User-Agent:

多くの善良なユーザはこれらの値に不正をはたらくことはないかもしれない。しかしながら、インターネットを経由して外部からプログラムに供給されるこれらの項目に、悪意の人物が攻撃パターンを混入するのは難しくない。

したがって、プログラムがブラウザから受け取って内部で使用する項目の値すべてについて入力検査を施す必要がある。

入力検査対象の網羅
図6-4: 入力検査対象の網羅

2. クライアント側スクリプトの検査ロジックが迂回される

JavaScript等、クライアント側スクリプトを用いてユーザの入力値を検査することがある。この方式は、サーバへのHTTPリクエストが発生せず処理が早い。ユーザ操作に迅速に応答できるのみならず、ネットワーク通信量を減らすことができ、有用な手段である。

しかし、クライアント側スクリプトはブラウザに預けられるものであるため、ユーザの手による機能停止やロジックの書き変えを禁止できない。悪意あるユーザは、JavaScript等で記述された検査ロジックを迂回して、攻撃パターンを含む悪意のデータをサーバ側プログラムに送り付けることができる。

迅速な応答でユーザに利便性を提供するのと同時に、サーバ側プログラムでも入力検査を省略せず行うことによって、攻撃パターンの侵入を防ぐ必要がある。

3. 数値範囲検査において攻撃を見逃す

PerlやPHP等一部のプログラミング言語において、文字列を整数値に変換する際のルールが厳しくないことが原因で、数値の範囲を検査するロジックにおいて攻撃パターンの侵入を見逃す場合がある。

例えば、ある入力値が数値として適切な値をもっていることを確認した上で処理に進むことを意図した次のような記述を想定する。

if ($a < 100 || $a > 200) {
	エラー処理
}
本来の処理

Webアプリケーションプログラムへの入力データはどれも文字列として与えられる。ここで変数 $a に次のような文字列データが与えられたとき、

$a = '123';

数値の範囲検査は意図通りにはたらく。ところが、$a に次のような値が与えられても、この値は「正しい」値であると判断されてしまう。

$a = '123<script>悪意のスクリプト</script>';

その理由は、処理系が文字列を数値に変換する際、先頭部分の数値として解釈できる範囲のみを変換対象として採用し、数値として解釈できない後続の文字列は無視するという振舞いをするためである。これはC言語の atoi() 関数等にしばしば見られる仕様である。

入力検査の際、数値が範囲内に収まっていることのみで判断するのは避けたほうがよい。文字種検査を行い、攻撃パターンの混在を検出する必要がある。

なお他の言語では、例えば、Java においては NumberFormatException例外が発生する等、少しでも数値として解釈する際に不審な内容が混在しているとエラーとして検出してくれる処理系もある。