入力値検証に関するチートシート

OWASP 作成
ジャンプ先: 移動検索
Cheatsheets-header.jpg

最終改訂日 (yy/mm/dd):2015/12/08

はじめに

この資料は、アプリケーションで適切な入力値検証を行うための、簡単でわかりやすい実用的なガイダンスを提供することに重点を置いています。

入力値検証の目的

入力値検証は、誤った形式のデータがシステムに入力されるのを最小限に抑えるために実行されます。入力値検証は、XSS や SQL インジェクションの一次的な防御方法ではありません。これらの攻撃については、出力エンコードと関連チートシートで取り上げています。

ホワイトリスト型の入力値検証

常に、ユーザー (攻撃者) のリクエストを処理するできるだけ早い段階で攻撃を防ぐことが推奨されます。入力値検証を使用すれば、アプリケーションで処理される前に不正な入力を検出できます。開発者はよくブラックリスト型の入力値検証を実行して「'」文字、文字列「1=1」、<script> タグのような攻撃文字や攻撃パターンを検出しようとしますが、これは非常に欠陥の多いアプローチです。概して、このようなフィルターに引っかからないようにすることは、攻撃者にとってたやすいからです。また、こうしたフィルターで 「'」文字を排除していると、「O'Brian」のような正当な入力までしばしば妨げてしまいます。

ホワイトリスト型の入力値検証は、ユーザーが入力するすべての入力フィールドに適しています。ホワイトリスト型の入力値検証では、何を許可するかを正確に定義します。当然、それ以外のものはいっさい許可されません。日付、社会保障番号、郵便番号、電子メール アドレスなど、構造が明確なデータの場合、開発者は一般に正規表現に基づくきわめて強力な検証パターンを定義して、入力内容を検証できます。入力フィールドがドロップダウン リストやラジオ ボタンのように事前定義された選択肢の 1 つを受け付ける場合には、そもそも入力されるものは、ユーザーに提示された値のいずれかと完全に一致する必要があります。検証が最も難しいフィールドは、ブログのエントリーのような、いわゆる "フリー テキスト" フィールドです。しかし、この種のフィールドでも、ある程度の検証は可能です。少なくとも、印刷不可能な文字をすべて排除することや、入力フィールドの最大サイズを定義することができます。

正規表現の開発は複雑になる場合があるので、このチートシートの対象範囲をはるかに越えています。正規表現の記述方法については、インターネット上に多くのリソースが存在します。たとえば、http://www.regular-expressions.info/「OWASP Validation Regex Repository (OWASP 検証のための正規表現リポジトリ)」 などです。次に、"ホワイトリスト" 型正規表現の例をいくつか示します。

ホワイトリスト型正規表現の例

郵便番号の検証 (5 桁 + 省略可能な - と 4 桁)

^\d{5}(-\d{4})?$

ドロップダウン リストから米国州を選択する場合の検証

^(AA|AE|AP|AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|
HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE| 
NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|
TX|UT|VT|VI|VA|WA|WV|WI|WY)$


Java での正規表現の使用例

 正規表現を使用して "zip" パラメーターを検証する例。
 
 private static final Pattern zipPattern = Pattern.compile("^\d{5}(-\d{4})?$");
 public void doPost( HttpServletRequest request, HttpServletResponse response) {
 	try {
 		String zipCode = request.getParameter( "zip" );
 		if ( !zipPattern.matcher( zipCode ).matches()  {
 			throw new YourValidationException( "Improper zipcode format." );
 		}
 		.. 検証が終了したので、必要な処理を実行します ..
 	} catch(YourValidationException e ) {
 		response.sendError( response.SC_BAD_REQUEST, e.getMessage() );
 	}
 }

オープンソースパッケージのなかには、ホワイトリスト検証機能が事前に定義されているものもあり、これを活用できます。次に例を示します。


入力値検証の必須事項:

  • ユーザーが制御するすべてのデータに適用する。
  • 許可する文字の種類を定義する (多くの場合は U+0020 から U+007E までであり、ほとんどの特殊文字は除外できます。また、制御文字が必要なことはまずありません)。
  • データの最小長と最大長を定義する ({1,25} など)。

クライアント側での検証とサーバー側での検証

クライアント側で JavaScriptを使って実行する入力値検証は、攻撃者による JavaScript の無効化や Web プロキシの使用で迂回される危険があることに注意してください。クライアント側で実行する入力値検証は、すべてサーバー側でも実行するようにしてください。

積極的なアプローチ

攻撃のバリエーションは莫大です。正規表現を使用して何が有効であるかを定義し、それ以外のものを受け取った場合は入力を拒否します。言い換えれば、"誤りとわかっているものを拒否する" のではなく、"正しいとわかっているものを許容する" というアプローチをとる必要があります。

たとえば、あるフィールドがユーザー名を受け取るとします。適切な正規表現では、データが [0-9a-zA-Z]{3,10} で構成されていることを検証します。データがこれに一致しない場合は拒否します。  
不適切なアプローチでは、悪意のある文字列のリストを作成し、ユーザー名が不適切な文字列を含んでいないことを単に検証するだけです。このアプローチの場合、不適切な可能性のある文字列をすべて想定したか、という疑問がつきまといます。

入力値検証の確実な使用

ユーザーから受け取るすべてのデータを悪意のあるデータとして扱い、アプリケーションで使用する前に検証してください。これには以下のデータが含まれます。

  • フォーム データ
  • URL のパラメーター
  • Hidden フィールド
  • Cookie データ
  • HTTP ヘッダー
  • 基本的に HTTP リクエスト内にあるすべての要素

入力値検証

ユーザーから受け取ったデータは、以下の観点からも検証が必要です。

1.想定している範囲に収まる値か (範囲外の値になっていないか)

2.入力データの長さ (たとえば、入力コントロールが 8 文字しか受け付けない場合は、データの受け取り時に文字数を検証する必要があります。入力文字数が 8 文字を超えることはできません)。

リッチユーザーコンテンツの検証

ユーザーが送信したリッチコンテンツの検証は非常に困難です。HTML Purifier (PHP)AntiSamybleach (Python) などの使用を検討してください。

Authors and Primary Editors

Dave Wichers - dave.wichers [at] aspectsecurity.com

Other Cheatsheets

Developer Cheat Sheets (Builder)

Assessment Cheat Sheets (Breaker)

Mobile Cheat Sheets

OpSec Cheat Sheets (Defender)

Draft Cheat Sheets