「検索フォームの値をそのまま SQL につなぐ」「入力された URL の画像をサーバが取ってくる便利機能」。どちらも、入力を"実行"に混ぜた瞬間に牙をむきます。SQL インジェクション(SQLi)では DB の中身が、SSRF ではクラウド(AWS)の一時鍵まで奪われます。
社内エンジニア向けセキュリティ勉強会(全6回)の第2回です。Laravel と FuelPHP の両方で危険なコードと安全なコードを並べ、「入力はデータとして扱い、コード(SQL)や宛先(URL)から分離する」という一本の原則で、新旧どちらのフレームワークでも両脆弱性を塞ぎます。
重心を置く SSRF では、url= のような便利機能から 169.254.169.254(EC2 インスタンスメタデータ)を叩かせ、IMDSv1 経由で IAM の一時認証情報が丸見えになるまでを疑似デモで追跡します。そのうえで、基盤(IMDSv2)・アプリ(送信先 URL の検証)・権限・検知の多層防御へ落とし込みます。
扱うトピック
- SQLi:文字列連結/補間の危険性、プレースホルダによる分離、識別子(カラム名・並び順)は許可リストで(Laravel の whereRaw/DB::raw、FuelPHP の DB::query の穴と対策)
- SSRF:攻撃が効く理由(内部ネットワークの信頼を悪用)、EC2 メタデータ経由の IAM 鍵窃取、IMDSv1 と IMDSv2 の違い
- 対策:許可リスト・内部IP遮断・DNS解決後のIP検証・リダイレクト追従禁止、IMDSv2 の強制、そして多層で守る考え方
持ち帰る3つの結論
1. 入力はコードに混ぜない = プレースホルダで分離する
2. 入力は宛先に混ぜない = 送信先 URL を検証する
3. 基盤と入口の多層で守る = IMDSv2 + URL 検証
レガシー保守(FuelPHP 1.x)でも「明日からできる」棚卸しと設定確認まで示します。
想定読者:入力をそのまま実行に混ぜていた"ちょっと前の自分"。
分類:OWASP A03:2021 Injection / CWE-89、OWASP A10:2021 SSRF / CWE-918