サニタイズ
ユーザー入力に含まれる有害なコードや不正な文字を除去・無害化する処理。XSS 対策では出力先に応じたエスケープと組み合わせて使う。
サニタイズ (サニタイゼーション) とは、ユーザーからの入力データに含まれる有害なコードや不正な文字列を除去・無害化する処理です。Web アプリケーションのセキュリティにおいて最も基本的な防御手段の一つであり、入力値を信頼せず必ず検証・変換するという原則に基づいています。サニタイズを怠ると、攻撃者がフォームや URL パラメータを通じて悪意のあるコードを注入し、データの漏洩やシステムの乗っ取りにつながる危険があります。
代表的な攻撃手法である XSS (クロスサイトスクリプティング) では、悪意のある JavaScript コードがユーザー入力を通じて Web ページに埋め込まれます。たとえば掲示板の投稿欄に <script>alert('XSS')</script> と入力された場合、サニタイズ処理がなければそのスクリプトが他のユーザーのブラウザで実行されてしまいます。SQL インジェクションでは、データベースクエリに不正な SQL 文が挿入され、データの改ざんや漏洩が発生します。
サニタイズの方法には複数のアプローチがあります。HTML エスケープは特殊文字を実体参照に変換する手法で、< を < に、> を > に置換します。ホワイトリスト方式 (許可リスト) は許可された文字やタグのみを通過させる方法で、リッチテキストエディタの出力を安全に表示する場合に有効です。ブラックリスト方式 (拒否リスト) は禁止パターンを除去しますが、未知の攻撃パターンに対応できないため、許可リスト方式の方が安全性は高いとされています。ユーザーが意図的に HTML を書ける機能では、許可リストを自前で組むより実績のある HTML サニタイザーライブラリを使うのが定石で、OWASP は DOMPurify を推奨しています。この種のライブラリは新しい回避手法に追随して修正されるため、定期的な更新が前提になります。また、サニタイズした後の文字列に手を加えると防御が無効になりうるので、サニタイズは出力直前の最後の工程に置きます。
実務では、サニタイズはバリデーション (入力値の妥当性検証) と組み合わせて使用します。バリデーションは「入力が期待する形式かどうか」を判定し、サニタイズは「入力を安全な形式に変換する」処理です。ここで取り違えやすいのが処理を行う場所です。OWASP の XSS 対策指針は、エスケープをデータが描画される場所のできるだけ近く (つまり出力する瞬間) で行うことを原則としています。入力を受け取った時点で一律に HTML エスケープして保存する設計は、その値が最終的に HTML・JavaScript・URL のどこへ出るのか分からないまま変換してしまうため、必要な防御が抜けたり、O'Hara のような正当な入力が二重エスケープで壊れたりします。入力時にやるべきなのは形式のバリデーション (許可する文字種や長さの検査) で、エスケープは出力先ごとに行う、と役割を分けると混乱しません。フレームワークの多くはテンプレートエンジンが出力時に自動エスケープする仕組みを備えており、自前で実装するよりそれを使う方が安全です。
サニタイズとエスケープは混同されがちですが、厳密には異なる概念です。サニタイズは危険な要素を除去または変換する包括的な処理を指し、エスケープは特定のコンテキスト (HTML、SQL、URL など) で特殊な意味を持つ文字を安全な表現に変換する処理です。出力先のコンテキストに応じて適切なエスケープ方式を選択することが重要で、HTML 出力には HTML エスケープ、SQL クエリにはパラメータ化クエリ (プリペアドステートメント) を使用します。OWASP の SQL インジェクション対策では、プリペアドステートメントと変数バインドが第一の防御に置かれ、入力をエスケープして SQL 文へ埋め込む方法は「強く非推奨」とされています (データベース製品ごとに規則が異なり壊れやすいため)。SQL についてはサニタイズで頑張るのではなく、コードとデータを分離する仕組みへ載せ替えるのが正解です。
文字数カウントの観点では、サニタイズ処理により文字列の長さが変化する点に注意が必要です。たとえば < が < に変換されると 1 文字が 4 文字に、& は & で 5 文字、" は " で 6 文字に増えます。データベースのカラム長やフォームの文字数制限を設計する際には、サニタイズ後の文字列長を考慮する必要があります。ユーザーが入力した文字数と、サニタイズ後にデータベースに保存される文字数が異なるケースは、バグの原因になりやすいポイントです。設計の目安としては、入力の文字数制限はユーザーが見ている生の文字列で判定し (エスケープ後の長さで弾くと、なぜエラーになったのか説明できません)、データベースのカラム長はエスケープ後の最悪ケース (1 文字が 6 文字になる) を見込んで確保する、と役割を分けておくと事故が起きにくくなります。