WordPressで考えるSSRF│localhostにアクセスする攻撃│Basic SSRF against the local server解説

Webアプリケーションには、外部サービスと連携するためにURLへHTTPリクエストを送る機能が実装されていることがあります。

例えば次のような機能です。

  • 外部APIからデータを取得する
  • RSSフィードを読み込む
  • Webhookを送信する
  • 外部画像を取得する

こうした機能は便利ですが、実装によってはサーバー自身が攻撃者の指定したURLへアクセスしてしまうことがあります。

この問題はSSRF(Server-Side Request Forgery) と呼ばれる脆弱性です。

SSRFでは、攻撃者がWebアプリケーションを経由して内部ネットワークや管理画面へアクセスできてしまうことがあります。

この記事では、PortSwiggerのWeb Security Academyラボ「Basic SSRF against the local serverを例に、SSRFの基本的な仕組みを整理します。

さらに、WordPressの構造に置き換えながら、どのような場面でSSRFが発生する可能性があるのかも解説します。

SSRFとは何か

SSRF(Server-Side Request Forgery)は、サーバーに任意のURLへリクエストを送らせる攻撃です。

Webアプリケーションは、外部サービスと連携するためにHTTPリクエストを送ることがあります。例えば次のような機能です。

  • 外部APIの取得
  • RSSの取得
  • Webhookの送信
  • 外部画像のダウンロード

しかし、ユーザー入力のURLをそのまま取得する実装になっている場合、攻撃者は任意のURLへサーバーをアクセスさせることができます。

これがSSRFです。


SSRFの基本│なぜ内部サーバーにアクセスできるのか

SSRFの本質は、攻撃者が直接アクセスできない内部リソースへ、Webアプリケーションを経由してアクセスすることです。

SSRFの基本構造
SSRFの基本構造の図

外部ユーザーは localhost や内部ネットワークへ直接アクセスできません。
しかしWebアプリケーションは内部ネットワークへアクセスできることがあります。

SSRFは、このアクセス権限の差を悪用する攻撃です。


インターネットと内部ネットワークの構造

多くのWebシステムでは、次のようなネットワーク構造になっています。

インターネットと内部ネットワークの構造
インターネットと内部ネットワークの構造の図

この構造では

  • 外部ユーザー → 内部ネットワークはアクセス不可
  • Webサーバー → 内部ネットワークはアクセス可能

という状態になります。

SSRFは、この仕組みを利用した攻撃です。


ラボ「Basic SSRF against the local server」の概要

今回のラボは、Basic SSRF against the local serverです。

このアプリケーションには在庫確認機能(Stock Check) が存在します。

商品ページで「Check stock」をクリックすると、アプリケーションは内部システムから在庫情報を取得します。

処理の流れは次のようになっています。

stock API処理の流れ
stock API処理の流れ

このとき、在庫APIのURLはstockApi パラメータで指定されています。


SSRF攻撃はどのように実行されるのか

Burp Suiteでリクエストを確認すると、次のパラメータがあります。

stockApi=

アプリケーションはこのURLを取得して在庫情報を表示しています。

つまり次のような処理です。

fetch(stockApi)

ここでURLを書き換えることが可能です。

localhostへアクセスするSSRF

まず /admin にアクセスすると、

Access denied

となり、管理画面には入れません。

しかし stockApi を次のように変更します。

stockApi=http://localhost/admin

するとWebアプリケーションがlocalhostへリクエストを送信し、管理画面のHTMLが返ってきます。

管理ユーザー削除

管理画面HTMLを確認すると、次のURLが見つかります。

http://localhost/admin/delete?username=carlos

これを stockApi に指定します。

stockApi=http://localhost/admin/delete?username=carlos

するとサーバーが内部管理画面へアクセスし、ユーザー carlosが削除されます。

これでラボは解決です。


なぜこのラボでSSRFが成立するのか

このラボでは、在庫確認機能がURLを指定してデータを取得する仕組みになっています。

つまり次のような処理です。

stockApi = user_input
response = fetch(stockApi)

ここで問題になるのは、URLの検証が行われていないことです。

本来は次のような制限が必要です。

  • localhost禁止
  • 内部IP禁止
  • APIドメインの制限

しかしこのラボでは、ユーザー入力URLをそのまま取得してしまいます。


よくあるSSRF攻撃パターン

SSRFはさまざまな形で利用されます。

localhost SSRF

今回のラボのように、

http://localhost

へアクセスさせるパターンです。

管理画面や内部サービスが対象になります。

内部ネットワークSSRF

次のような内部IPをスキャンする攻撃です。

http://192.168.x.x

社内システムや内部APIが対象になります。

クラウドメタデータSSRF

クラウド環境では、次のURLが重要です。

http://169.254.169.254

ここには、

  • IAMキー
  • クラウド設定

などの機密情報が存在する場合があります。


WordPressに置き換えるとSSRFはどこで起きるのか

WordPressでも外部URLを取得する機能は多く存在します。

例えば次のようなケースです。

外部API取得

wp_remote_get()

RSS取得

fetch_feed()

Webhook

外部サービスへのHTTPリクエスト。

外部画像取得

URLを指定して画像をダウンロードする機能。

もしユーザー入力をそのままHTTPリクエストに使用すると、SSRFが発生する可能性があります。


開発者視点でのSSRF対策

SSRFを防ぐためには、サーバーがアクセスできるURLを制御することが重要です。

ドメイン制限(許可リスト)

アクセス可能なドメインを限定します。

allowed_domains = ["api.example.com"]

localhost / 内部IPを禁止

次のアドレスはブロックする必要があります。

  • localhost
  • 127.0.0.1
  • 内部IP
  • 169.254.169.254

リダイレクトの検証

リダイレクトを利用して内部URLへ誘導される場合があります。

そのため、

  • リダイレクトを制限
  • リダイレクト先URLの再検証

が必要です。

ユーザー入力URLを使わない設計

可能であれば、

  • URLを固定
  • IDでAPIを指定

などの設計にする方が安全です。


SSRFはなぜ見つけにくいのか

SSRFは他の脆弱性と比べて、発見が難しいことが多いと言われています。
その理由は、攻撃がサーバー側で実行されるためです。

通常の攻撃では、攻撃者のブラウザとWebサーバーの通信を確認すれば挙動を把握できます。

しかしSSRFの場合、実際のリクエストは次のような流れになります。

攻撃者 → Webアプリケーション → 内部サーバー

つまり、内部サーバーへのアクセスは攻撃者の環境からは直接確認できません。

そのため、

  • レスポンスの変化
  • エラーメッセージ
  • タイミングの違い

などを手がかりに挙動を推測する必要があります。


ログからSSRFの兆候を見つける

SSRFはサーバー側で実行されるため、サーバーログに痕跡が残ることがあります。

例えば次のようなログです。

  • 内部アドレスへのHTTPリクエスト
  • localhostへのアクセス
  • 内部APIへの不自然なアクセス

Webサーバーや内部サービスのログを確認することで、SSRF攻撃の兆候が見つかる場合があります。


SSRFを発見するためのセキュリティ診断チェックポイント

SSRFはURLをサーバーに送らせる機能を見つけることがスタートです。
以下の手順で調査すると効率よく発見できます。

① 外部URLを受け取る機能を探す

まずは、ユーザーがURLを入力・指定できる機能を探します。

チェック対象

  • API連携機能(URL指定)
  • RSSフィード取得
  • Webhook送信先
  • 画像URL入力
  • 外部データ取得機能

見るポイント

  • フォーム入力欄にURLがある
  • パラメータにURLっぽい値がある(例:url=, api=, feed=

ポイント

「URLを入力できる場所=SSRF候補」と考える

② リクエスト内容を確認する(Burp or DevTools)

次に、その機能が実際にどんなリクエストを送っているか確認します。

確認方法

  • Burp Suiteでリクエストをキャプチャ
  • またはブラウザのDevTools(Networkタブ)

見るポイント

  • stockApi= のようなURLパラメータがあるか
  • サーバー側でURLを取得している形跡

stockApi=http://example.com/api

この時点で書き換え可能なら怪しい。

③ URLを書き換えて挙動を確認する

ここがSSRF診断の核心です。

実際にURLを書き換えて、サーバーの挙動を確認します。

localhostアクセスを試す

http://localhost
http://127.0.0.1

チェックポイント

  • レスポンスが変わるか
  • HTMLが返ってくるか
  • エラー内容が変わるか

内部IPを試す

http://192.168.0.1
http://10.0.0.1

反応があれば内部ネットワークアクセスの可能性あり。

クラウドメタデータを試す

http://169.254.169.254

AWSなどでは重要情報が取れる可能性あり。

④ レスポンスの変化を観察する

SSRFは見た目で分かりづらいので、変化を注意深く見ます。

チェックポイント

  • レスポンス内容が変わる
  • ステータスコードが変わる
  • タイムアウトが発生する
  • エラーメッセージが変わる

  • 通常:Invalid URL
  • localhost指定:HTMLが返る → SSRFの可能性

⑤ リダイレクトの挙動を確認する

フィルタ回避のために重要なポイントです。

テスト方法

  • 外部URL → 内部URLへリダイレクトさせる

http://attacker.com → http://localhost/admin

チェックポイント

  • リダイレクト先までアクセスされるか

⑥ ログから異常な通信を探す

SSRFはサーバー側で実行されるため、ログにヒントが残ることがあります。

見るべきログ

  • Webサーバーログ
  • アプリケーションログ

チェックポイント

  • localhostへのアクセス
  • 内部IPへの通信
  • 不自然な外部リクエスト

SSRF対策(WordPress・Webアプリ共通)

SSRFを防ぐためには、サーバーがアクセスするURLを制御することが重要です。

  • ユーザー入力のURLをそのまま使用しない
  • アクセス可能なドメインを制限する(許可リスト)
  • localhost や内部IPへのアクセスを禁止する

※具体的な対策方法は別記事で詳しく解説します。


WordPressでSSRFが発生しやすい実装例

WordPressでは、外部URLへリクエストを送るための関数が用意されています。

注意が必要な関数

  • wp_remote_get()
  • wp_remote_post()
  • fetch_feed()

これらは便利な反面、ユーザー入力のURLをそのまま渡すとSSRFの原因になります。

実際の危険なコード例

例えば、次のような実装です。

$url = $_GET['url'];
$response = wp_remote_get($url);

このコードでは、ユーザーが指定したURLに対して、サーバーがそのままHTTPリクエストを送ってしまいます。

なぜ危険なのか

この状態では、攻撃者が次のようなURLを指定できます。

  • http://localhost
  • http://127.0.0.1
  • http://192.168.x.x

その結果、サーバーが内部ネットワークへアクセスしてしまい、管理画面や内部APIに到達する可能性があります。

実際のチェック方法

WordPressサイトを調査する際は、次のポイントを確認します。

  • プラグイン内で wp_remote_get() が使われていないか
  • ユーザー入力(GET / POST)をそのままURLに使っていないか
  • URLの制限(ドメイン制限・IP制限)があるか

ポイント

ユーザー入力 → URL → HTTPリクエスト

この流れがあればSSRFを疑う。


まとめ

SSRFは、サーバーに任意のURLへアクセスさせる攻撃です。

今回のラボでは、

  • URL指定の在庫API
  • URL検証不足
  • サーバーの内部アクセス権限

という条件が揃うことでSSRFが成立しました。

WordPressでも、

  • API取得
  • RSS取得
  • Webhook

などの機能では同様の問題が発生する可能性があります。

外部URLを扱う機能を実装する場合は、アクセス可能なURLを厳格に制御することが重要です。



このブログの運営環境

  • WordPress
  • GeneratePress
  • エックスサーバー

エックスサーバー公式サイト