EXERCISE 90分

ストーリー

高橋アーキテクト
理論は十分だ。ここからは実際に手を動かそう

高橋アーキテクトが架空のシステム要件書を配りました。

高橋アーキテクト
このオンライン医療予約システムに対して、脅威モデリングを実施してほしい。DFDの作成から、STRIDE分析、DREAD評価、セキュリティ要件の定義まで、一気通貫でやってみよう
あなた
90分で全部ですか?
高橋アーキテクト
現場では限られた時間で判断を下す必要がある。完璧を目指さなくていい。重要なのは”プロセスを実践すること”だ

課題概要

項目内容
対象システムオンライン医療予約システム
課題数5つ
合計時間90分
評価基準各課題の成果物を作成すること

対象システムの概要

  • 患者がWebブラウザから医療機関の予約を行う
  • 医師が自分のスケジュールと予約を管理する
  • 管理者がユーザーやシステム設定を管理する
  • 外部の決済サービス(Stripe)と連携する
  • 診療記録は暗号化して保存する

課題1: DFD(データフロー図)を作成しよう(20分)

以下の要素を含むDFDを作成してください。

要件

  • 外部エンティティ:患者、医師、管理者、決済サービス
  • プロセス:認証サーバー、予約API、決済API、通知サービス
  • データストア:ユーザーDB、予約DB、診療記録DB
  • 信頼境界を明確にする
解答例(自分で作成してから確認しよう)
                      ─ ─ ─ ─ 信頼境界(外部) ─ ─ ─ ─
┌──────┐                                          ┌──────────┐
│ 患者  │──HTTPS──→┌───────────┐                   │ 決済     │
└──────┘          │ API       │──API Call──→       │ サービス  │
┌──────┐          │ Gateway   │                    │ (Stripe) │
│ 医師  │──HTTPS──→│           │                    └──────────┘
└──────┘          └─────┬─────┘
┌──────┐                │
│ 管理者 │──HTTPS──→     │
└──────┘     ─ ─ ─ ─ ─ ┼ ─ ─ ─ 信頼境界(内部) ─ ─ ─

               ┌────────▼─────────┐
               │ 認証サーバー       │
               └────────┬─────────┘

          ┌─────────────┼─────────────┐
          │             │             │
    ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
    │ 予約API   │ │ 決済API   │ │ 通知      │
    │           │ │           │ │ サービス   │
    └─────┬─────┘ └─────┬─────┘ └───────────┘
          │             │
    ┌─────▼─────┐ ┌─────▼─────┐
    │ ユーザーDB │ │ 予約DB    │
    │ 診療記録DB │ └───────────┘
    └───────────┘

信頼境界:
- 外部境界: インターネット ↔ API Gateway
- 内部境界: API Gateway ↔ 内部サービス群
- データ境界: サービス ↔ データベース

ポイント:

  • 信頼境界を3層で定義(外部、内部、データ)
  • 外部エンティティと内部プロセスを明確に分離
  • 決済サービスは外部エンティティとして扱う

課題2: STRIDE分析を実施しよう(20分)

DFDの各コンポーネントに対してSTRIDE分析を行い、主要な脅威を3つ以上特定してください。

分析対象

  • 予約APIプロセス
  • 認証サーバー
  • 診療記録DB
解答例(自分で作成してから確認しよう)

予約APIプロセスのSTRIDE分析:

カテゴリ脅威説明
S(なりすまし)他の患者になりすまして予約認証トークンの窃取
T(改ざん)予約料金の改ざんリクエストパラメータの変更
R(否認)予約キャンセルの否認患者が「キャンセルしていない」と主張
I(情報漏洩)他の患者の予約情報閲覧IDOR脆弱性
D(DoS)大量予約リクエストで予約システムダウンボットによる自動予約
E(権限昇格)患者が医師の管理機能にアクセス認可チェックの不備

認証サーバーのSTRIDE分析:

カテゴリ脅威説明
S(なりすまし)ブルートフォースでのログイン突破パスワード総当り
T(改ざん)JWTトークンの改ざん弱い署名アルゴリズム
I(情報漏洩)エラーメッセージからのユーザー存在確認ユーザー列挙攻撃

診療記録DBのSTRIDE分析:

カテゴリ脅威説明
T(改ざん)診療記録の不正な変更DBへの直接アクセス
I(情報漏洩)暗号化されていない診療記録の漏洩バックアップファイルの流出
D(DoS)DBの過負荷によるサービス停止大量クエリ攻撃

課題3: DREAD評価を行おう(15分)

課題2で特定した脅威の中から上位3つを選び、DREADスコアリングを行ってください。

解答例(自分で作成してから確認しよう)
脅威D(被害)R(再現)E(悪用)A(範囲)D(発見)平均優先度
診療記録の情報漏洩1075967.4High
IDOR による予約情報漏洩798687.6High
ブルートフォース攻撃797397.0High

分析の根拠:

  • 診療記録は医療情報(HIPAA対象)のため被害が最大
  • IDORは再現性が高く、自動ツールで発見しやすい
  • ブルートフォースはツールで自動化可能だが影響は個別ユーザー

課題4: セキュリティ要件を定義しよう(20分)

DREAD評価の結果に基づき、優先度の高い脅威に対するセキュリティ要件を3つ定義してください。

解答例(自分で作成してから確認しよう)

SEC-DATA-001: 診療記録の暗号化

  • カテゴリ: データ保護
  • STRIDE: I(情報漏洩)
  • DREADスコア: 7.4
  • 受け入れ基準:
    • 診療記録はAES-256-GCMで暗号化して保存する
    • 暗号化キーはAWS KMSで管理する
    • 復号はアプリケーション経由でのみ可能
    • DBの直接参照では暗号文のみ表示される
  • 優先度: Must

SEC-AUTHZ-001: 予約情報のアクセス制御

  • カテゴリ: 認可
  • STRIDE: I(情報漏洩)/ E(権限昇格)
  • DREADスコア: 7.6
  • 受け入れ基準:
    • 患者は自分の予約のみ閲覧・変更可能
    • 医師は自分に関連する予約のみ閲覧可能
    • 他の患者の予約IDでアクセスすると403エラー
    • 全APIエンドポイントで所有者チェックを実施
  • 優先度: Must

SEC-AUTH-001: ブルートフォース対策

  • カテゴリ: 認証
  • STRIDE: S(なりすまし)
  • DREADスコア: 7.0
  • 受け入れ基準:
    • 5回連続失敗でアカウントを30分間ロック
    • IPベースのレートリミット(1分間に10回まで)
    • ログイン失敗を監査ログに記録
    • CAPTCHA(3回失敗後に表示)
  • 優先度: Must

課題5: セキュアな設計パターンを適用しよう(15分)

課題4で定義したセキュリティ要件を実現するための設計パターンを選択し、適用方法を記述してください。

解答例(自分で作成してから確認しよう)
// 1. ゲートキーパーパターン:全リクエストの認証・認可チェック
const securityMiddleware = [
  rateLimiter({ windowMs: 60000, max: 60 }),
  helmet(),
  authenticate,
  auditLogger,
];

// 2. 入力バリデーションパイプライン
const appointmentSchema = z.object({
  doctorId: z.string().uuid(),
  date: z.string().datetime(),
  reason: z.string().min(1).max(500),
});

// 3. リソースの所有者チェック(IDORの防止)
const ownershipCheck = (resourceType: string) => {
  return async (req: Request, res: Response, next: NextFunction) => {
    const resource = await getResource(resourceType, req.params.id);
    if (!resource) return res.status(404).json({ error: "Not found" });

    const canAccess =
      resource.patientId === req.user.id ||
      resource.doctorId === req.user.id ||
      req.user.role === "admin";

    if (!canAccess) {
      return res.status(403).json({ error: "Forbidden" });
    }
    next();
  };
};

// 4. 診療記録の暗号化
const encryptMedicalRecord = (record: string, key: Buffer): string => {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
  const encrypted = Buffer.concat([
    cipher.update(record, "utf8"),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();
  return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted.toString("hex")}`;
};

適用パターンの対応:

セキュリティ要件適用パターン
診療記録の暗号化エンベロープ暗号化
予約情報のアクセス制御ゲートキーパー + 所有者チェック
ブルートフォース対策トークンバケット + アカウントロック

達成度チェック

課題テーマ完了
課題1DFDの作成[ ]
課題2STRIDE分析[ ]
課題3DREAD評価[ ]
課題4セキュリティ要件定義[ ]
課題5セキュアな設計パターン適用[ ]

まとめ

ポイント内容
DFDデータの流れと信頼境界を可視化する
STRIDE6カテゴリで漏れなく脅威を洗い出す
DREAD定量評価で優先度を決定する
要件定義脅威分析の結果を実装可能な要件に変換する

チェックリスト

  • DFDを作成して信頼境界を定義できた
  • STRIDE分析で脅威を体系的に特定できた
  • DREADスコアリングで優先度を判定できた
  • セキュリティ要件をSMART原則で定義できた
  • 適切な設計パターンを選択して適用できた

次のステップへ

お疲れさまでした。脅威モデリングの実践演習が完了しました。 次はStep 2のチェックポイントです。


推定所要時間: 90分