Overview
入力バリデーション(Input Validation)とは、ユーザーや外部システムからの入力データが、期待される形式・型・範囲・長さに合致しているかを検証する処理です。サニタイゼーション(Sanitization:無害化)は、入力データから潜在的に危険な文字やコードを除去・変換する処理を指します。これらはWebアプリケーションセキュリティの最も基本的かつ重要な防御策です。
入力バリデーションとサニタイゼーションが不十分なアプリケーションは、SQLインジェクション、XSS(クロスサイトスクリプティング)、コマンドインジェクション、パストラバーサルなど、あらゆるインジェクション攻撃に対して脆弱になります。OWASP Top 10でもインジェクション攻撃は常に上位に位置しており、その根本原因は入力の検証不足にあります。
セキュリティの原則として「すべての入力は信頼できない」という前提に立つことが重要です。フォームの入力値だけでなく、HTTPヘッダー、Cookie、URLパラメータ、ファイルアップロード、API経由のデータなど、外部から受け取るすべてのデータを検証対象とする必要があります。
Details
ホワイトリスト vs ブラックリスト
ホワイトリスト(許可リスト)方式は、許可する入力パターンを明示的に定義し、それ以外をすべて拒否するアプローチです。例えば、電話番号フィールドには数字とハイフンのみを許可するといった形です。ブラックリスト(拒否リスト)方式は、危険と判断される入力パターン(例:scriptタグ)をリストアップして拒否するアプローチです。
セキュリティの観点からはホワイトリスト方式が圧倒的に推奨されます。ブラックリスト方式では、攻撃者が新しいエンコーディングや難読化手法を使用してフィルターをバイパスするリスクが常に存在します。完全なブラックリストを作成することは事実上不可能であり、攻撃手法の進化に追従し続ける必要があります。
サーバーサイド vs クライアントサイド バリデーション
クライアントサイドバリデーション(HTML5のrequired属性、JavaScriptによる検証など)はユーザー体験の向上に役立ちますが、セキュリティ対策としては一切信頼できません。攻撃者はブラウザの開発者ツールやプロキシツール(Burp Suite等)を使用して、クライアントサイドのバリデーションを完全にバイパスできます。
サーバーサイドバリデーションは、セキュリティ上の必須要件です。クライアントサイドでバリデーションを行っていても、サーバーサイドで同等以上のバリデーションを必ず実施してください。すべてのセキュリティ判断はサーバーサイドで行うのが大原則です。
出力エスケープ(Output Encoding)
入力バリデーションだけでは不十分であり、データを出力する際のコンテキストに応じた出力エスケープが不可欠です。同じデータでも、出力先によって異なるエスケープ処理が必要になります。
- HTMLエスケープ:HTMLコンテンツに出力する際に < > & " ' をHTMLエンティティに変換
- JavaScriptエスケープ:JavaScript文字列に出力する際に特殊文字をUnicodeエスケープに変換
- SQLエスケープ:SQL文に出力する際にシングルクォートなどを適切にエスケープ(ただしプリペアドステートメントの使用が推奨)
- URLエスケープ:URLパラメータに出力する際に特殊文字をパーセントエンコーディングに変換
プリペアドステートメント(パラメータ化クエリ)
プリペアドステートメントは、SQLインジェクション攻撃に対する最も効果的な防御策です。SQL文の構造とデータ(パラメータ)を完全に分離し、データベースエンジンがパラメータを常に「データ」として扱うため、攻撃者が入力にSQL文を混入させても、それがSQLコマンドとして実行されることはありません。
文字列連結によるSQLクエリの組み立ては、絶対に避けるべきアンチパターンです。すべてのデータベースアクセスでプリペアドステートメントまたはORMのクエリビルダーを使用してください。
ORMの安全な使用
ORM(Object-Relational Mapping)フレームワークは、多くの場合内部的にプリペアドステートメントを使用するため、基本的にSQLインジェクションからの保護を提供します。しかし、ORMにも「生SQLクエリ」を実行する機能があり、これを不適切に使用するとSQLインジェクションの脆弱性が発生します。
ORMを使用する場合でも、生SQLクエリの使用時には必ずパラメータバインドを行い、ユーザー入力を直接クエリ文字列に埋め込まないようにしてください。また、ORMのバージョンを最新に保ち、既知の脆弱性への対応を確実にすることも重要です。
正規表現DoS(ReDoS)
ReDoS(Regular Expression Denial of Service)は、脆弱な正規表現パターンに対して巧妙に構成された入力文字列を送信することで、正規表現エンジンの処理時間を指数関数的に増大させ、サービス拒否状態を引き起こす攻撃です。
「Evil Regex」と呼ばれる脆弱なパターンには、ネストされた量指定子(例:(a+)+)や、バックトラッキングが爆発的に増大する交互選択が含まれます。対策として、正規表現のタイムアウトを設定する、ReDoS検出ツール(例:recheck、safe-regex)で正規表現を事前に検証する、可能であれば正規表現以外の文字列処理に切り替えることが推奨されます。
Security Measures
- 01サーバーサイドでのホワイトリスト型バリデーションの実装:すべてのユーザー入力に対して、サーバーサイドでホワイトリスト型のバリデーションを実施してください。データ型、長さ、範囲、フォーマットを厳密に定義し、期待される形式に合致しない入力はすべて拒否しましょう。クライアントサイドのバリデーションはUXの補助としてのみ位置づけてください。
- 02出力コンテキストに応じたエスケープ処理:データを出力する際は、出力先のコンテキスト(HTML、JavaScript、SQL、URL、CSS)に応じた適切なエスケープ処理を必ず行ってください。テンプレートエンジンの自動エスケープ機能を活用し、手動でのエスケープ漏れを防止しましょう。
- 03プリペアドステートメントの徹底使用:データベースアクセスではすべてのクエリでプリペアドステートメント(パラメータ化クエリ)を使用してください。文字列連結によるSQLクエリの構築は絶対に避け、ORMの生SQLクエリを使用する場合も必ずパラメータバインドを行いましょう。
- 04入力長とリクエストサイズの制限:各入力フィールドに適切な最大長を設定し、HTTPリクエスト全体のサイズにも上限を設けてください。バッファオーバーフローやReDoS、大量データ送信によるDoS攻撃のリスクを軽減できます。
- 05正規表現の安全性検証:バリデーションに正規表現を使用する場合は、ReDoS脆弱性がないことをsafe-regexやrecheckなどのツールで検証してください。正規表現にはタイムアウトを設定し、処理時間の上限を設けることも重要です。
- 06Unicode正規化の一貫した適用:バリデーション処理の前にUnicode正規化(NFC等)を適用し、視覚的に同一だが異なるバイト列を持つ文字(例:全角と半角、合成文字と分解文字)によるバリデーションバイパスを防止してください。多言語対応のアプリケーションでは特に重要です。
Incidents
📋 Log4Shell(CVE-2021-44228)— 入力検証失敗の代表例(2021年)
2021年12月に公表されたLog4Shell脆弱性は、Java向けロギングライブラリApache Log4jにおいて、ログに記録される入力文字列の検証が不十分だったことに起因します。Log4jは入力文字列中のJNDI Lookup構文(${jndi:ldap://...})を自動的に解釈・実行する機能を持っており、攻撃者はHTTPヘッダー(User-Agent等)やフォーム入力にこの構文を含めるだけで、リモートコード実行(RCE)が可能でした。
この脆弱性はCVSSスコア10.0(最高値)を記録し、世界中の数百万のシステムに影響を与えました。Log4jを使用するApache Struts、Apache Solr、Minecraft、Steam、iCloudなど無数のサービスが影響を受けました。この事件は、ログ出力のような一見安全に見える処理においても入力検証が不可欠であることを強く示しています。
📋 ReDoS攻撃によるサービス停止
Node.jsエコシステムにおいて、正規表現DoS(ReDoS)脆弱性が原因でサービスが停止するインシデントが複数報告されています。例えば、広く使用されていたnpmパッケージ「minimatch」や「moment.js」に含まれていた脆弱な正規表現パターンが、悪意のある入力によって処理のハングアップを引き起こしました。
特にNode.jsのようなシングルスレッドの実行環境では、1つの正規表現評価がブロックされるだけでサーバー全体が応答不能になるため、影響が深刻です。攻撃者は数十文字程度の入力でサーバーを数分間ハングさせることが可能であり、正規表現パターンのセキュリティレビューの重要性を示す事例となっています。
📋 Unicode正規化バイパス攻撃
複数のWebアプリケーションにおいて、Unicode正規化の不整合を悪用した入力バリデーションバイパス攻撃が報告されています。攻撃者はUnicodeの特殊文字(全角文字、合字、結合文字など)を使用してバリデーションフィルターを通過し、正規化後にインジェクション攻撃を成立させました。
代表的な例として、SQLインジェクションフィルターがASCIIのシングルクォート(')をブロックしていたのに対し、攻撃者がUnicode上の類似文字(例:U+FF07 全角アポストロフィ)を使用してフィルターを回避し、データベース処理段階でASCII文字に正規化されてインジェクションが成立するケースがあります。この対策として、バリデーション前のUnicode正規化の統一的な適用が不可欠です。