■ 1. バリデーションに関する誤解
- 集中型バリデーションへの誤解: バリデーションをモデルのみで集中的に行い、コントローラー(入力)でバリデーションをしないという誤った考え方が一般的である。
- セキュリティ対策への誤解:
- 「入力データはバリデーションできない」「どんな入力も受け付けるべき」「ホワイトリスト型は無理」といった考え方は、セキュアなソフトウェア構築において問題がある。
- 「入力バリデーションはセキュリティ対策ではない」という考えは、セキュリティ対策の定義(=リスクを変化させる全ての施策)を理解していない。
- 基本原理:
- プログラムは「妥当なデータ」以外では正しく動作できないため、入力バリデーションは必須である。
- 遅すぎるエラー(下層でのエラー)はセキュアではない。
■ 2. 3種類のバリデーションと役割
- 多層防御の原則: セキュリティを確保するためには、バリデーションは多層構造で実施する必要がある。OWASPもこれを推奨している。
- 3種類のバリデーション:
- (1) 入力バリデーション:
- 役割: アプリケーションの入り口(MVCならコントローラー)で、形式的な検証を行う。
- 目的: プログラムが正しく処理できない「不正な入力データ」を拒否し、Fail Fast(できるだけ早く失敗させる)の原則に従う。
- 方法: 原則としてホワイトリスト型で検証する。データ形式とデータ型は異なるため、データ型チェックだけでは不十分である。
- (2) ロジックバリデーション:
- 役割: プログラムの処理本体(MVCならモデル)で、論理的な検証を行う。
- 目的: データの論理的な整合性をチェックし、改ざんされたデータなどを検出する。
- 入力エラーとの違い: バリデーションは「不正なデータ」を検出し処理を中止する。一方、入力エラーは「妥当だが入力ミス」のデータを扱い、処理を継続する。
- (3) 出力バリデーション:
- 役割: 出力時(MVCならビュー)でデータの無害化を行う。
- 目的: エスケープやAPIが利用できない場合、フェイルセーフ対策としてデータの正しさを検証する。
- 原則: ソフトウェアの不具合などにより不正なデータが出力処理に混入するリスクに備える。この段階でのエラーは、入力またはロジックにバグがあることを意味する。
■ 3. ソフトウェアの粒度とバリデーション
- アプリケーションレベル:
- 前提: 信頼できないシステムとやり取りするため、入力バリデーション、ロジックバリデーション、出力バリデーションのすべてが必須である。
- マイクロサービス化の課題: モノリシックなアプリケーションを分割する場合、各サービス/APIの「入り口」でバリデーションを行わないと脆弱になる。
- モジュール/関数レベル:
- 前提: アプリケーションレベルでバリデーションが完了していることを前提とすることができる。
- 効率化: 契約プログラミングやユニットテストを利用することで、開発時には厳格なバリデーションを行い、運用時には不要なバリデーションを省略することが可能となる。
■ 4. バリデーションエラーの扱い
- エラーの定義: バリデーションエラーは、アプリケーションが受け入れ不可能な「不正なデータ」のみを指す。「入力ミス」は含めない。
- エラー発生時の対応: 不正なデータが検出された場合、プログラムのバグか攻撃かのどちらかである。
- 対応手順:
- (1) エラーを無視せず、ログを取る。
- (2) エラーを監視する。
- (3) 直ちに処理を停止する。
- (4) 可能な対応(警告レスポンス、セッション破棄、IPブロックなど)を行う。
- 結論: バリデーションは、単なる入力チェックではなく、ソフトウェアの安全性を確保するための重要なセキュリティ設計要素である。入力バリデーションなしにセキュアなアプリケーションは構築できない。