プログラマのための IT 教科書

セキュリティを設計に組み込む

この部の 6 / 8 章 ・ 全体で 67 / 76 章 ・ 読了目安 45 分

この章を読むとできるようになること
  • 設計レビューでセキュリティの問いを出せる
  • 既定で拒否・多層防御を設計に反映できる
  • インシデント時に何をすべきか知っている

ここまでの章で、個別の脆弱性と対策を見てきました。 最後に、それをいつ・どうやって設計に組み込むかを扱います。

なぜなら、セキュリティは後から足せないからです。

リリース前日に診断を受ける
→ 「認可の設計が根本的に足りません」
→ 直すには設計からやり直し
→ リリース延期か、リスクを承知で出すかの二択

この状況を作らないことが、この章の目的です。

なぜ「後から」では間に合わないのか

かつては、開発の最後に「セキュリティ試験」の工程がありました。 リリースが年に数回で、そこで直す時間があったからです。

しかし今は、週に何度もデプロイします(なぜ DevOps が必要になったか)。 最後にまとめて検査する方式では、速度に追いつきません。

そこで、工程の左側(設計・実装)に前倒しするという考え方が主流になりました。 これをシフトレフトと呼びます。

設計時   脅威を洗い出す        ← ここが最も安い
実装時   静的解析・レビュー
CI       依存の脆弱性チェック
リリース前 診断
運用中   監視・報告受付

修正コストは、後の工程になるほど跳ね上がります。 設計時なら会話1回、リリース後なら数千万円ということもあります。

脅威モデリング — 設計時に何を考えるか

難しく聞こえますが、4つの問いに答えるだけです。

1. 何を作っているのか(データはどこを流れるか)
2. 何がうまくいかないか(どう攻撃されるか)
3. それに対して何をするか
4. うまくやれたか(確認方法)

まず、データの流れを描く

[利用者] --HTTPS--> [Web] --> [API] --> [DB]
                      │         │
                      │         └--> [外部決済API]
                      └--> [オブジェクトストレージ]

そして、信頼境界を引きます。

信頼境界 = 「ここから先は信用できない」という線
□ インターネット と 自社サービス の間
□ 自社サービス と 外部サービス の間
□ 一般利用者 と 管理者 の間
□ テナントA と テナントB の間

境界をまたぐところに、必ず検証が必要です。

STRIDE — 抜け漏れを防ぐ分類

思いつきで考えると、必ず漏れます。分類に沿って考えると網羅できます。

分類脅威対策の方向
Spoofingなりすまし認証(認証と認可の実装)
Tampering改ざん署名・完全性チェック(暗号と鍵の扱い)
Repudiation否認(やっていないと言う)監査ログ・署名
Information Disclosure情報漏洩暗号化・権限(認証と認可の実装)
Denial of Serviceサービス妨害レート制限・負荷制限(性能と負荷対策)
Elevation of Privilege権限昇格認可・最小権限(Web の脆弱性を体系的に)
「この API に対して、なりすましは? 改ざんは? 権限昇格は?」
と順に当てはめていく
新人でもできる簡易版

設計レビューで、この3つを聞くだけで価値があります。

1. 「このデータは誰が見られますか? 見られてはいけない人は誰ですか?」
2. 「この操作を、他人の ID を指定して実行できませんか?」
3. 「ここに悪意のある値を入れたら、どこまで届きますか?」

専門知識がなくても聞けるうえに、 実際に設計の穴が見つかることがよくあります(技術者の社会的責任)。

設計の原則

最小権限

□ 必要な権限だけを与える。「念のため広めに」をやらない
□ 人・サービスアカウント・AI エージェント(AI とセキュリティ)すべてに適用する
□ 期間も限定する(一時的な権限は、期限付きで)

権限は、与えるより剥がすほうが難しいので、最初が肝心です。

既定で拒否

✕ 「危ないものを列挙して禁止する」   → 漏れる
○ 「安全なものを列挙して許可する」   → 漏れても安全側に倒れる
□ 認可はミドルウェアで全ルートに適用し、公開ルートだけを明示的に除外(認証と認可の実装)
□ ファイル形式は許可リスト(ファイルとストレージ)
□ 外部通信先は許可リスト(SSRF 対策。Web の脆弱性を体系的に)

多層防御

1つの対策が破られても、次で止まるようにします。

XSS 対策の例:
  1. 入力を検証する
  2. 出力時にエスケープする(textContent)
  3. CSP で外部スクリプトを実行させない
  4. Cookie に HttpOnly を付け、盗まれても使わせない

どれか1つでよいわけではありません。 すべてやります。

攻撃面を減らす

□ 使っていないエンドポイントを消す
□ 管理画面をインターネットに公開しない
□ デバッグ機能を本番で無効にする
□ 依存ライブラリを増やしすぎない(ライセンスと依存ライブラリ)

存在しない機能は攻撃されません。 最も確実な対策です。

安全に失敗する

□ 認可の判定でエラーが起きたら、「拒否」に倒す
□ 例外時に、詳細を利用者に返さない
□ 障害時のフォールバックが、検証を飛ばしていないか(性能と負荷対策)
エラー時に許可してしまう実装
allowed, err := authz.Check(ctx, user, resource)
if err != nil {
    log.Warn("認可チェックに失敗")
    allowed = true            // ✕ 認可サービスが落ちたら、全員が通る
}

「動き続けること」を優先して、安全側を捨てている例です。

性能と負荷対策の静的安定性では「依存が落ちても動き続ける」ことを推奨しましたが、 認可については話が別です。判断できないなら拒否してください。

実装と CI に組み込む

□ **SAST**(静的解析)    — コードから危険なパターンを検出
□ **SCA**(依存の検査)   — ライブラリの既知の脆弱性(ライセンスと依存ライブラリ)
□ **シークレット検出**     — 鍵をコミットしていないか
□ **DAST**(動的検査)    — 動いているアプリに実際にリクエストを送る
□ **IaC の検査**          — Terraform の設定ミス(公開バケット等。Terraform と Infrastructure as Code)

すべて CI に入れて、PR ごとに自動で回します(CI/CD)。

検出結果を放置しない

ツールを入れると、最初は大量の指摘が出ます。

□ 全部を一度に直そうとして、結局誰も見なくなる
□ 「いつもの警告」になり、本当の問題が埋もれる
1. まず**重大なものだけ**をブロック対象にする
2. 既存の指摘は「既知」として記録し、期限を決めて減らす
3. **新規に追加された指摘は、必ず0にする**  ← これが最も効く

「今より悪くしない」から始めるのが、続けるコツです(設計の基礎の技術的負債)。

診断とテスト

手段内容
脆弱性診断専門業者やツールによる検査。リリース前や定期的に
ペネトレーションテスト実際に攻撃を試みる。より実践的
バグバウンティ外部の研究者に報告してもらう制度
社内のレビュー設計レビュー・コードレビューでの観点(ビットとバイト)
□ 診断の指摘は、深刻度と実際の到達可能性で優先順位を付ける(ライセンスと依存ライブラリ)
□ 「指摘された箇所だけ」直すと、同じ種類の別の箇所が残る
□ **原因の種類ごとに横展開して確認する**

インシデント対応

起きた時にどう動くかを、起きる前に決めておきます。

1. 検知     監視・利用者からの報告・外部からの通報
2. 初動     報告する。証拠を保全する(ログを消さない。エンジニアと法律)
3. 封じ込め 被害の拡大を止める(該当機能の停止、権限の剥奪、鍵の無効化)
4. 根絶     原因を除去する
5. 復旧     サービスを戻す
6. 学習     ポストモーテム(監視とオンコール)と、再発防止の実装
□ 誰に連絡するか、連絡先の一覧を作っておく
□ 業務時間外に起きた場合の手順を決めておく
□ 法務・広報・経営への報告経路を確認しておく(エンジニアと法律)
新人がやること・やらないこと
やること:
  □ 気づいたら、すぐ報告する
  □ 見たこと・やったことを、時刻つきで記録する
  □ 指示を待つ

やらないこと:
  □ 自分で調査を広げる(証拠を壊す、被害を広げる)
  □ ログや証跡を消す
  □ 外部に話す(SNS を含む。ルールを守る — 情報を扱う者の日常)
  □ 一人で判断する

「大したことないと思ったので報告しませんでした」が最も重い判断ミスです。 影響範囲の判断は、個人がするものではありません。

外部からの報告を受け取れるようにする

□ 脆弱性の報告窓口を公開する(security@ など)
□ 報告してくれた人に、敵対的に対応しない

善意の報告者を法的に脅すと、次からは報告されずに公開されます。 これは技術の問題ではなく、組織の姿勢の問題です。

新人が今日からできること

□ 自分の PR に、Web の脆弱性を体系的にのチェック観点を当てる
□ 設計レビューで「このデータは誰が見られますか」と聞く
□ 「エラー時にどちらへ倒れますか(許可 or 拒否)」と聞く
□ 依存を追加する時、既知の脆弱性を確認する(ライセンスと依存ライブラリ)
□ ログに秘密情報が出ていないか確認する
□ 何かおかしいと感じたら、すぐ報告する

新しい機能の設計レビューに参加しました。セキュリティの観点で、新人でも出せる価値のある質問はどれですか。

実務の落とし穴まとめ

  1. リリース直前に診断 — 設計の問題は直せない。前倒しする
  2. 危ないものを禁止する方式 — 漏れる。許可リストにする
  3. 1つの対策で満足する — 多層防御。破られた次を用意する
  4. エラー時に許可へ倒す — 認可は「判断できないなら拒否」
  5. 検出ツールの指摘を放置 — 慣れて見なくなる。新規だけでも0にする
  6. 指摘された箇所だけ直す — 同じ種類を横展開で確認する
  7. インシデントで自分で調査を広げる — 証拠を壊し、被害を広げる
  8. 報告を迷う — 影響範囲の判断は個人がするものではない
  9. 報告者に敵対的に対応する — 次からは公開されてから知ることになる

まとめ

  • セキュリティは後から足せない。工程の左側に前倒しする(シフトレフト)
  • 脅威モデリングは4つの問い。データの流れを描き、信頼境界を引く
  • 抜け漏れは STRIDE の分類で防ぐ
  • 原則は、最小権限・既定で拒否・多層防御・攻撃面の削減・安全に失敗する
  • 認可のエラー時は拒否に倒す。可用性より安全を優先する場面がある
  • CI に SAST / SCA / シークレット検出 / IaC 検査を入れ、 新規の指摘だけは0にする
  • インシデントは 検知 → 報告と証拠保全 → 封じ込め → 根絶 → 復旧 → 学習
  • 新人は、報告して記録して指示を待つ。調査を広げない
  • 設計レビューで**「誰が見られますか」「他人の ID なら?」と聞くだけ**で価値がある

公式ドキュメント・参考資料

対象リンク
OWASP Top 10https://owasp.org/www-project-top-ten/
OWASP チートシート集https://cheatsheetseries.owasp.org/
OWASP 脅威モデリングhttps://owasp.org/www-community/Threat_Modeling
IPA「安全なウェブサイトの作り方」https://www.ipa.go.jp/security/vuln/websecurity/
IPA 情報セキュリティ10大脅威https://www.ipa.go.jp/security/10threats/
JPCERT/CChttps://www.jpcert.or.jp/
NIST Secure Software Development Frameworkhttps://csrc.nist.gov/projects/ssdf

IPA の「情報セキュリティ10大脅威」は毎年更新され、 日本国内で実際に起きている被害の傾向が分かります。 組織向けと個人向けが分かれているので、両方に目を通す価値があります。

次の章では、同じ「守る」話を法律の側から見ます。

読み終わったら記録しておくと、目次で進み具合が分かります。