


バックエンドの変更で、アップロードやユーザー入力からの攻撃を防ぐ
アップロードされたファイル、ZIPやTAR、リクエストの値を扱うバックエンドのコードをAIに変えさせる時に使う。外から来るデータの行き先をたどり、使う前に検証し、似た処理の全部に同じ直しを入れ、セキュリティのチェックリストとlint・テストの合格で終える。
このAIルールを使うには
## 変更の前に、外から来るデータの行き先と似た処理を全部探す
ユーザーが認証済みであっても、アップロードファイル、アーカイブの内容、リクエストパラメータ、マニフェスト、メタデータ、デバイス識別子は攻撃者に制御されている可能性があると想定する。
機密性の高いコード経路を変更する前に、次を行う。
1. 信頼できないデータがどこから入り、どのように変換され、どのファイル操作、プロセス、データベース、描画、リダイレクト、ネットワーク操作へ到達できるかをすべて特定する。
2. 同じ操作を行う同系統の実装を探す。代替形式、APIとWebビュー、バイナリとソースの処理経路、旧来の呼び出し箇所も対象に含める。
3. ビューやハンドラーへ場当たり的な検査を分散させず、集約されたセキュリティヘルパーを再利用または拡張する。
4. 過去の脆弱性パターンを参照できる場合は確認し、特に1つの経路しか保護していない不完全な修正に注意する。
5. importとローカル規約の一貫性を保ち、必要なlintと対象を絞ったテストを、正常終了するまで実行する。
同等の経路から脆弱な操作へまだ到達できるなら、そのセキュリティ修正は不完全である。
## リクエストとアップロードを入口で検証し、ログインと権限を求める
未加工の入力がパス、コマンド引数、クエリ値、リダイレクト、描画文字列、外部接続先ホストになる前に検証する。
- 型付きフォームまたはスキーマを主要な検証層として使う。
- 有効値が既知の有限集合であるパラメータには、選択肢が限定されたフィールドを使う。
- フィールド固有の拒否ロジックは検証層へ置き、検証に失敗した場合は標準のエラー応答を返す。
- 識別子をパスや検索に使う前に、厳密な形式に照らして検証する。
- アップロードのマジックバイト、サイズ上限、拡張子の許可リストを確認する。拡張子だけでは不十分である。
- マニフェストとメタデータの値を、信頼できない入力として扱う。
機密性の高い処理を担うハンドラーには、該当する制御をすべて適用する。
- 認証
- ロールまたは権限による認可
- 明示的なHTTPメソッド制限
- ブラウザーから始まる状態変更に対するCSRF保護
テンプレートのエスケープを無効にしたり、信頼できない内容を安全だと指定したりしてはならない。自動エスケープを行うテンプレートの外で応答を組み立てる場合は、出力先の文脈に合わせて値をエンコードする。
## ファイルのパスとZIP・TARの展開を、決めたフォルダの中に収める
ファイルシステムのパスには、2層の保護を使う。
1. トラバーサル要素、絶対パス、エンコードによる回避、不正な文字など、危険な未加工形式を拒否する。
2. パスを組み立てた後、正規化して解決し、意図したルートの内側に収まっていることを確認する。
通常ファイルを想定する操作でファイルシステム上のオブジェクトを読む前に、シンボリックリンク、名前付きパイプ、デバイスファイル、その他の想定外の種類を拒否する。
TARを展開する場合は、次に従う。
- トラバーサル、絶対パス、デバイスファイル、展開先の外へ出るリンクを拒否する、実行環境が提供するメンバー単位かつ種類を認識する展開フィルターを優先する。
- 名前だけ、または`abspath`だけによる検査に依存してはならない。これらはシンボリックリンクを解決しない。
- 安全な組み込みフィルターを利用できない場合は、シンボリックリンクとハードリンクを拒否し、`realpath`で展開先を解決して、各メンバーの展開直前に検証する。
- 検証と展開の間にファイルシステムの状態が変わる可能性があるため、一括検証後の一括展開を避ける。
ZIPを展開する場合は、次に従う。
- 展開前に、すべてのメンバー名をトラバーサルの有無について検証する。
- 提案された展開先を解決し、展開ルートの内側に収まっていることを確認する。
- そのメンバーが両方の検査に合格した後にだけ展開する。
失敗したすべてのガードは、`continue`、`return`、`raise`のいずれかで危険な操作を止めなければならない。実行を止めずに警告をログへ記録するだけでは、セキュリティ制御にならない。
## SQLやシェルコマンドなど、使う場所ごとにユーザー入力を無害にする
- サブプロセスの引数はリストとして渡す。信頼できない入力をシェルコマンド文字列へ決して埋め込まない。
- パラメータ化されたORMまたはクエリビルダーの操作を使う。文字列整形でSQLを決して組み立てない。
- 自動エスケープの対象外で描画する前に、ユーザーが制御できる内容をエスケープする。
- SVGなどの能動的な形式は、表示前に無害化する。
- ログインジェクションを防ぐため、ユーザー由来のログフィールドから改行と制御文字を取り除く。
- 応答ヘッダーへ入れる前に、安全なファイル名を生成する。
- 検証済みの相対リダイレクト先だけを許可する。
- 外部リクエストの前にホストを解決して検証し、ループバック、プライベート、リンクローカル、マルチキャスト、その他の禁止されたアドレス範囲を拒否する。
単一の汎用サニタイザーではなく、文脈ごとの検証を適用する。データベースフィルターに使える値でも、ファイル名、シェルコマンド、HTML断片、ログ項目、リダイレクト、URLでは危険な場合がある。
## セキュリティのチェックリストで仕上げ、項目ごとに根拠を示す
ファイルI/Oまたはユーザー入力を伴うすべての変更について、該当する項目を確認する。
- [ ] パスを組み立てる前に、未加工の入力を検証している。
- [ ] 組み立てたパスを正規化して解決し、意図したルートの内側へ収めている。
- [ ] 読み取り前に、想定外のリンク、パイプ、ファイル種別を拒否している。
- [ ] 展開前に、アーカイブの各メンバーを個別に検証している。
- [ ] シェル引数を文字列へ埋め込まずに渡している。
- [ ] 描画する値をエスケープし、能動的な内容を無害化している。
- [ ] 外部接続先ホストとリダイレクト先を制限している。
- [ ] ユーザー由来のログ値を無害化している。
- [ ] データベースアクセスでパラメータ化された操作を使っている。
- [ ] すべての拒否分岐が危険な操作を防いでいる。
- [ ] 同等のコード経路へ同じ修正を適用している。
- [ ] 対象を絞ったテストで、受理する入力、拒否する入力、回避試行を網羅している。
- [ ] lintと関連テストが終了コード0で完了している。
完了した各確認の根拠を報告し、検証できなかった経路を明示する。
