概要
セキュアコーディングは、脆弱性を開発工程で作り込まないための実装原則・慣行の集合です。SQLi・XSS・バッファオーバーフローなどの典型的な脆弱性はほぼすべて実装の誤りに起因するため、コーディング段階での対処が最も費用対効果が高い対策です。SC試験の午後問題ではソースコードの断片を見て脆弱性を特定・修正する問題が頻出です。
仕組みと動作原理
入力値検証の原則
検証は「入口」と「出口」の両方で行う
| タイミング | 目的 | 例 |
|---|---|---|
| 入力時検証(Allowlist) | 許可した形式以外を拒否 | 電話番号は数字とハイフンのみ |
| 出力時エスケープ | 文脈に応じてエンコード | HTML出力 → HTMLエンティティ変換 |
許可リスト(Allowlist)vs 拒否リスト(Denylist)
| 方式 | 説明 | 推奨度 |
|---|---|---|
| 許可リスト | 明示的に許可した値・形式だけを受け入れる | ◎ 推奨 |
| 拒否リスト | 既知の危険なパターンを拒否する | △ 漏れが生じやすい |
拒否リストは攻撃者が新しい迂回手法を使うと無効になるため、可能な限り許可リストを使います。
出力エスケープのコンテキスト
同じ入力値でも出力先によって必要なエスケープが異なります。
| 出力コンテキスト | エスケープ方法 | 注意点 |
|---|---|---|
| HTMLタグ内テキスト | & < > " ' → HTMLエンティティ | デフォルトで必要 |
| HTML属性値 | 上記+属性に応じた処理 | href は URL の検証も必要 |
| JavaScript | \u00XX 形式でUnicodeエスケープ | HTMLエスケープと異なる |
| SQL | プリペアドステートメント | エスケープではなくバインド変数が根本対策 |
| シェルコマンド | シェルメタ文字を回避 | 可能な限りシェル呼び出しを避ける |
エラー処理の原則
情報漏洩を防ぐエラーハンドリング
# 悪い例(スタックトレースを表示してしまう)
try:
result = db.query(sql)
except Exception as e:
return str(e) # DB構造・ファイルパスが漏洩する
# 良い例
try:
result = db.query(sql)
except Exception:
logger.exception("DB query failed") # 詳細はサーバログへ
return "エラーが発生しました" # ユーザには汎用メッセージのみ
エラーメッセージで漏洩しやすい情報:
- データベースのテーブル名・カラム名(SQLエラー)
- 内部ファイルパス(例外スタックトレース)
- ソフトウェアバージョン(Serverヘッダ・エラーページ)
- 存在するユーザIDの有無(「パスワードが違います」vs「ユーザが存在しません」)
依存ライブラリ(OSS)の管理
サプライチェーン攻撃のリスク
現代のアプリケーションは多数の外部ライブラリに依存しています。直接依存だけでなく、間接依存(依存の依存)にも脆弱性が含まれる可能性があります。
| リスク | 説明 | 対策 |
|---|---|---|
| 既知脆弱性 | CVEが公開済みのライブラリを使用 | SCA(ソフトウェア構成分析)ツール |
| 悪意のあるパッケージ | タイポスクワッティング・乗っ取り | パッケージ名の慎重な確認・ロックファイル |
| メンテナンス停止 | セキュリティパッチが出なくなる | 依存ライブラリの定期的な棚卸し |
| ライセンス違反 | GPL等の感染性ライセンス | ライセンス確認ツール |
SBOM(ソフトウェア部品表): 使用するすべてのソフトウェアコンポーネントと依存関係を一覧化した文書。脆弱性管理に活用されます。
危険なコーディングパターン
| パターン | リスク | 対策 |
|---|---|---|
| 文字列連結でSQL構築 | SQLインジェクション | プリペアドステートメント |
innerHTML へのユーザ入力反映 | XSS(DOM型) | textContent を使用 |
eval() の使用 | 任意コード実行 | 避ける |
| ハードコードされた認証情報 | 認証情報漏洩 | 環境変数・シークレット管理ツール |
| 平文でのパスワード保存 | 認証情報漏洩 | bcrypt・Argon2 などの適切なハッシュ |
| 不十分な乱数 | セッションID予測 | CSPRNG(暗号学的擬似乱数生成器)を使用 |
SC試験での頻出ポイント
- 検証は「入口」ではなく「出口(出力コンテキスト)」が根本対策:SQLi は出力先が SQL なので、SQL 向けのバインド変数が対策
- エラーメッセージの情報漏洩:攻撃者にシステム内部情報を与えない
- ハードコードされた認証情報の危険性:Gitリポジトリに含まれると永続的に残る
- 依存ライブラリの脆弱性管理:Log4Shell(Log4j の脆弱性)のような事例が午後で出題
- セッションIDの要件:十分なエントロピー・HTTPS 限定・適切な有効期限・ログアウト時の無効化
よくある誤問・ひっかけパターン
誤り① 「フロントエンドで入力値検証していればサーバ側検証は不要」→ 誤。クライアント側の検証はユーザ体験向上のためのもので、API を直接叩けば回避できます。サーバ側での検証が必須です。
誤り② 「エラーを握りつぶせば安全」→ 誤。エラーをログに残さずに無視すると障害調査ができなくなります。「ユーザには汎用メッセージ、ログには詳細」が正しいパターンです。
誤り③ 「最新バージョンを使えば脆弱性はない」→ 誤。新バージョンにも未知の脆弱性(ゼロデイ)が存在し得ます。また直接依存のアップデートが間接依存の脆弱性を解消するとは限りません。
関連用語
- SQLインジェクション — セキュアコーディングで防ぐ代表的な脆弱性
- XSS(クロスサイトスクリプティング) — 出力エスケープで防ぐ脆弱性
- セキュリティバイデザインとSDLC — セキュアコーディングを組み込む開発プロセス
- APIセキュリティ — セキュアコーディングのAPI実装への応用
重要キーワード
| 用語 | 説明 |
|---|---|
| 許可リスト(Allowlist) | 明示的に許可した値・形式のみ受け入れる入力検証方式 |
| 出力エスケープ | 出力コンテキスト(HTML・SQL・JS等)に応じた文字エンコード |
| SBOM | ソフトウェア部品表。使用する全コンポーネントの一覧 |
| SCA | ソフトウェア構成分析。依存ライブラリの既知脆弱性を検出するツール |
| CSPRNG | 暗号学的に安全な擬似乱数生成器。セッションIDやトークン生成に使用 |
| サプライチェーン攻撃 | 依存ライブラリや開発ツールを通じてアプリケーションに悪意のあるコードを混入させる攻撃 |