【メモ】セキュア実装の基本原則
はじめに
脆弱性を知ることと、安全に実装できることは別です。
実務では、入力値検証、出力エスケープ、認可チェック、エラーハンドリング、依存関係管理のような基本動作の積み上げで守りを作ります。1
この章では、セキュリティ技術入門で最初に身につけたいセキュア実装の原則を整理します。
セキュア実装は「後から足す機能」ではない
実装の最後にセキュリティ対応をまとめて入れる考え方では、抜け漏れが起きやすくなります。
むしろ、次の段階ごとに考えるべきです。
- 何を守るのか
- どこが入力か
- どこが出力か
- 誰が何をしてよいか
- 失敗時に何を見せるか
この視点がないと、仕様どおり動くが安全ではない実装になりやすくなります。
脅威モデリングを軽くでも入れる
脅威モデリングは、難しい図を作ることが目的ではありません。1
最低限、次の問いを考えるだけでも効果があります。
- どのデータが重要か
- どこから入力されるか
- どこで権限チェックが必要か
- 失敗すると何が起きるか
設計前にこれを考えると、入力値検証や認可チェックの置き場所が見えやすくなります。
入力値検証
入力値検証では、「何でも受け取って後で考える」を避けます。1
見るべき観点は次のとおりです。
- 型
- 長さ
- 形式
- 範囲
- 許可した値かどうか
重要なのは、危険なものを何となく除くのではなく、受け入れる条件を明確にすることです。
出力エスケープ
出力では、表示先や埋め込み先に応じて安全な扱いが必要です。1
同じ文字列でも、HTMLに出すのか、JavaScript文脈に入れるのか、属性値に使うのかで注意点が変わります。
そのため、入力時の検証だけで安心せず、出力時に文脈ごとの安全性を確保する必要があります。
認可チェックを機能の中心に置く
認可チェックは、画面の見た目だけでは不十分です。
ボタンを隠しても、APIやバックエンドで許していれば意味がありません。
認可は、「このユーザはこの操作をしてよいか」をサーバ側の実処理で確認する前提で設計すべきです。1
安全なエラーハンドリング
エラーは隠しすぎても、出しすぎても問題になります。1
利用者向けには必要以上の内部情報を出さず、運用者向けには原因追跡できるログを残すという分け方が重要です。
注意したいのは次の点です。
- スタックトレースや内部構造をそのまま見せない
- 秘密情報をエラーメッセージへ含めない
- 調査に必要な情報は安全なログへ残す
ライブラリと依存関係の管理
安全なコードを書いても、利用ライブラリが古ければ脆弱性を抱えることがあります。1
そのため、依存関係では次を意識します。
- 使っているものを把握する
- 更新計画を持つ
- 放置されたライブラリを漫然と積み上げない
- アップデート影響を確認する
起こしやすい誤り
動けばよいで実装を確定する
仕様上動いても、入力、権限、エラー、ログの観点で安全でなければ、実務では完成とは言えません。
フロント側だけで制御する
入力制御やボタン表示の制御だけで満足すると、バックエンド側の防御が抜けます。
エラーを出さないことを優先しすぎる
問題を隠しても安全にはなりません。
必要なのは、利用者に出す情報と、運用で追える情報を分けることです。
日常で意識したい原則
- 守る対象を先に考える
- 入力、出力、権限を分けて見る
- 認可は実処理で確認する
- 内部情報を出しすぎない
- 依存関係も実装の一部として管理する
ミニ確認
- 入力値検証で重要なのは、何を受け入れるか、それとも何を禁止するか
- 出力エスケープが必要なのはなぜか
- 認可チェックを画面だけに置くのが危険な理由は何か
- ライブラリ管理がセキュリティに関わるのはなぜか