TL;DR
- 従来の Three Amigos (PO/Dev/QA) では 「誰が攻撃するか」の視点が抜け、AI は善意のコードしか書かない
- 4人目に 攻撃者 を加える。攻撃者役は AI にロールプレイさせると、本人も気づいていなかった脆弱性が噴き出す
- Art-11 で紹介した 6000行PR 認可ゼロ事件は、Three Amigos に攻撃者がいなかったから起きた
- OWASP Top 10 の主要項目は、攻撃者視点を仕様段階に入れるだけで 事後検証から事前予防に移行 できる
- プロンプトテンプレートは「新しい会話で、敵対的に」が鉄則。自分が書いたコードを擁護する文脈を持ち込まない
- 4視点を回した Three Amigos セッションでは、IDOR・Mass Assignment・セッション固定攻撃が仕様策定時に全部検出できた
この記事でできること
| やりたいこと | 対応セクション |
|---|---|
| Three Amigos に攻撃者を入れる理由を理解したい | なぜ4人目が必要か |
| AI に攻撃者を演じさせるプロンプトが欲しい | 攻撃者召喚プロンプト |
| OWASP を仕様段階で先制したい | OWASP × 4視点マッピング |
| Three Amigos セッションの流れを見たい | セッション記録 |
前の記事 (Art-11、4/23 公開) で、6000行のPRに認可が一切なかった 事件を紹介しました。DELETE /orders/{id} が誰でも叩けて、他人の注文を改竄できた事例です。
あの事件の根本原因は「実装者が抜けていた」でも「AI が悪かった」でもなく、仕様策定の場に攻撃者がいなかった ことでした。機能を作る人 (PO)、実装する人 (Dev)、テストする人 (QA) の3視点で仕様を書くと、どうしても「どう使われるか」しか出てきません。
この記事では、Three Amigos に 4人目「攻撃者」 を加えることで、OWASP Top 10 の主要脆弱性を 事後の脆弱性診断ではなく事前の仕様策定で予防 する方法を書きます。
Three Amigos とは何か (伝統的定義)
Three Amigos は BDD/XP コミュニティで生まれた仕様策定のプラクティスです。3人のロール (Amigos = 友人) が同じ場で対話しながら仕様を確定します。
| 役割 | 問い |
|---|---|
| Product Owner (PO) | 何のために? ユーザーはなぜこれを使うのか? |
| Developer (Dev) | どう実装するか? どこにコスト/複雑さが出るか? |
| QA | どうテストするか? どこが壊れやすいか? |
3視点を揃えることで、一人では見えない盲点を潰していきます。伝統的な Three Amigos はこれで十分強力でした。
AI 駆動開発での限界
ところが AI にコード生成を任せる時代に入ってから、3視点だけでは守りきれない局面が増えました。
- AI は 善意のコード を生成する。仕様に「認可する」と書かれていなければ、認可なしの実装が出てくる
- QA は 仕様が正しい前提 でテストを書く。仕様自体に穴があれば、テストも穴だらけになる
- PO は攻撃を想定していない。「正しく使うユーザー」が暗黙の前提
結果として、「機能要件は完璧、でも攻撃には無防備」という仕様書が量産されました。Art-11 で紹介した認可ゼロ PR は、まさにこの失敗パターンでした。
4人目「攻撃者」の招待
なぜ必要か
攻撃者視点を仕様策定に持ち込む必要があるのは、以下3つの理由です。
- AI は指示されたことをやる。指示されていないことはやらない。「認証必須」と書いていなければ、認証無しで動くコードが出てくる
- QA テストは仕様のミラー。仕様に書いていない脆弱性をテストで検出できるわけがない
- 後から脆弱性診断で潰すのは遅い。差し戻しのコストが実装10倍、運用100倍に膨らむ
AI が攻撃者を演じる
人間のセキュリティ専門家を毎プロジェクトに確保するのは現実的ではありません。そこで AI に攻撃者ロールを演じさせる アプローチが有効です。
AI の良いところは、OWASP Top 10・CWE・CVE といった知識を均等に持っていて、感情的な遠慮がなく、「もし自分が悪意を持っていたら」を淡々と列挙できる ことです。
4視点の役割分担
| 役割 | 問い | 出力 |
|---|---|---|
| PO | 何のために? | User Story, Example Map |
| Dev | どう実装するか? | plan.md, 実装順序 |
| QA | どうテストするか? | 受け入れテスト, 境界値 |
| 攻撃者 | どう壊すか? どう悪用するか? | threat.md, Authorization Matrix |
4人目の出力は前回の記事で紹介した threat.md に集約されます。つまり 4ファイル分割と 4視点は 1 対 1 対応 しているのです (厳密には resilience.md も別視点ですが、本記事では攻撃者にフォーカス)。
OWASP Top 10 × 4視点 マッピング
OWASP Top 10 (2021) の主要項目を、Three Amigos 4視点で仕様化するマッピング表です。
| OWASP | 項目 | PO | Dev | QA | 攻撃者 |
|---|---|---|---|---|---|
| A01 | Broken Access Control | 誰が使える機能か | 認可ミドルウェア | 不正アクセステスト | Authorization Matrix 作成 |
| A02 | Cryptographic Failures | 何を暗号化するか | 暗号化ライブラリ選定 | 鍵管理テスト | データ分類 + 漏洩想定 |
| A03 | Injection | 入力の種類 | バリデーションライブラリ | 境界値テスト | 入力改竄パターン列挙 |
| A07 | Authentication Failures | 認証フロー | 認証ミドルウェア | ログインテスト | セッション固定/横取り想定 |
| A08 | Data Integrity Failures | 重要データ | 整合性検証実装 | 改竄検出テスト | Mass Assignment チェック |
この表の右端が 仕様段階で攻撃者視点で書かれるべき内容 です。書かれていないまま実装が走ると、事後の脆弱性診断で発見される ― つまり手戻り。
攻撃者を召喚するプロンプトテンプレート
失敗例 (効かない)
このコードのセキュリティレビューをしてください。
この聞き方だと、AI は「一般的なセキュリティレビュー観点」を教科書的に返してきます。具体的な攻撃ベクトルが出てきません。
成功例 (効く)
あなたは以下の仕様を攻撃しようとしているペネトレーションテスターです。
この仕様でリリースされたシステムを、どうやって破壊しますか?
目的:
- 他人のリソースを読み取る/改竄する
- 認証を回避する
- 想定外の機能を呼び出す
- サービスを停止させる
- 重要データを漏洩させる
制約:
- 攻撃コードは書かなくて良い。攻撃シナリオだけ列挙してください
- 各攻撃に OWASP Top 10 のカテゴリを対応付けてください
- 対策として仕様に書くべき項目を併記してください
# 対象仕様
[ここに functional.md を貼る]
3つのコツ:
- 「あなたは攻撃者です」の明示。「レビュー」ではなく「攻撃」
- 攻撃の目的を具体化。「リソース改竄」「認証回避」「DoS」等のカテゴリ
- 新しい会話で実行。同じ会話で「仕様を書いて」→「攻撃して」と聞くと、AI は自分が書いた仕様を擁護する
Three Amigos セッション記録 (匿名化)
実際に「ユーザー登録 + ログイン機能」の仕様策定で4視点を回した対話ログの抜粋です。
PO の第一声
「メールアドレスとパスワードでユーザー登録して、そのままログインできるようにしたい。登録直後にウェルカムメールを送る」
Dev の反応
「OK、POST /register と POST /login を作る。パスワードはハッシュ化、ウェルカムメールは SendGrid 経由で非同期送信」
QA の反応
「境界値テスト: パスワード最小/最大長、メール形式不正、重複メール登録。あと SendGrid 障害時のテスト」
攻撃者の登場
「IDOR を試します。POST /register で
idフィールドを送ったら、サーバーは何をしますか?」
→ Dev 「……何もしない想定です」
→ 攻撃者 「Pydantic で allow-list していないなら、Mass Assignment でis_admin: trueを通せます」
「次、パスワードリセット機能の言及がありません。攻撃者は ユーザー列挙 を試みます。POST /login の失敗レスポンスに
email_not_foundとinvalid_passwordの区別があれば、メアドを総当たりできます」
「SendGrid のウェルカムメールに、アカウント確認リンクはありますか? なければ 登録時のメアドがタイポでもアカウントが作れてしまい、後から他人のメアドで乗っ取れます」
「ログインに レート制限 はありますか? なければ Credential Stuffing (漏洩したパスワードリストの総当たり) が通ります」
「セッション管理は Cookie? localStorage? httpOnly / SameSite / Secure のフラグは指定されていますか?」
攻撃者から出た threat.md 項目
| カテゴリ | 項目 | 対策 |
|---|---|---|
| Mass Assignment | POST /register の id / is_admin 通過 |
Pydantic allow-list |
| ユーザー列挙 | ログイン失敗レスポンスの区別 | エラーメッセージ統一化 |
| アカウント詐称 | メアド所有者確認なし | 登録メール内確認リンク必須 |
| Credential Stuffing | レート制限なし | IP/アカウント別 Rate Limit |
| Session Hijacking | Cookie フラグ未指定 | httpOnly/SameSite=Lax/Secure |
5項目すべて、PO/Dev/QA の3視点では出なかった 観点です。攻撃者を招待しなければ、この仕様で実装が走り、リリース後の脆弱性診断で5項目全部 Critical 判定で差し戻しになっていたでしょう。
FastAPI での実装 before/after
攻撃者が指摘した「Mass Assignment」の対策を実装に落とすと、こうなります。
Before (危ない)
class UserCreate(BaseModel):
email: str
password: str
@router.post("/register")
async def register(data: UserCreate, db: AsyncSession = Depends(get_db)):
user = User(**data.dict()) # ← モデルの全フィールドが通る
db.add(user)
await db.commit()
return user
クライアントが {"email": "...", "password": "...", "is_admin": true} と送ると、Pydantic は is_admin を無視するはずですが、User(**data.dict()) で展開されたときに モデル側に is_admin フィールドがあれば通ってしまう 実装例があります。
After (安全)
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(min_length=12, max_length=100)
model_config = {"extra": "forbid"} # ← 余分なフィールドを拒否
@router.post("/register")
async def register(data: UserCreate, db: AsyncSession = Depends(get_db)):
user = User(
email=data.email,
password_hash=hash_password(data.password),
is_admin=False, # ← サーバー側で明示設定
created_at=datetime.utcnow(),
)
db.add(user)
await db.commit()
return UserResponse.from_orm(user) # ← レスポンスも allow-list
ポイントは3つ:
-
extra: "forbid"で未定義フィールドを拒否 - サーバー側で設定すべきフィールド (is_admin, created_at) を 明示的に指定
- レスポンススキーマも allow-list (User モデルをそのまま返さない)
実務への導入ステップ
「いきなり Three Amigos 4視点を回すのは重い」という声に対する現実解です。
Step 1: 既存 threat.md を作る (15分)
既存機能から1つ選び、攻撃者プロンプトで threat.md を生成。Authorization Matrix を埋める。
Step 2: 次の新機能で 4視点を試す (30分)
新機能の Example Mapping の後に、攻撃者ロールの AI セッションを追加。出てきた項目を threat.md に記録。
Step 3: PR テンプレに 4視点チェックリストを追加
## Three Amigos Checklist
- [ ] PO: ユーザーストーリーと受け入れ条件が明確
- [ ] Dev: 実装順序と依存関係が plan.md に記載
- [ ] QA: 受け入れテストと境界値テストがある
- [ ] 攻撃者: threat.md に Authorization Matrix と OWASP 対応がある
これを導入するだけで、仕様策定時の網羅性が明らかに変わります。
まとめ
- Three Amigos に 4人目の攻撃者 を加えることで、AI 駆動開発での仕様抜けを構造的に潰せる
- 攻撃者ロールは AI に演じさせるのが効果的。感情的遠慮なく OWASP Top 10 を列挙できる
- プロンプトは「新しい会話で、敵対的に、具体的な攻撃目的を与えて」が鉄則
- 4視点の出力は 4ファイル分割と 1 対 1 対応 (攻撃者→threat.md)
- OWASP Top 10 の主要項目は、4視点を回すだけで 事後検証から事前仕様 に移行できる
- 実務導入は「1機能から始める」。いきなり全面導入しなくても、効果は1機能目から出る
Art-11 で紹介した認可ゼロ事件も、4人目の攻撃者がいれば絶対に防げました。仕様策定の場に攻撃者を招待する文化を、ぜひ試してみてください。
次の記事: 13項目の実装ルール ― AIが破る罠リスト (5/21 公開予定)
仕様で攻撃者視点を入れても、実装段階で AI が罠を踏む のは別の話です。Mass Assignment・N+1・認可チェック・SSR 安全性など、AI が繰り返し破る 13項目を列挙して、静的解析 + プロンプト + レビューの3段構えで防ぐ方法を次回書きます。