こんにちは!システム開発やWebサービスの運用、お疲れ様です。
セキュリティの世界に足を踏み入れたばかりの頃って、専門用語ばかりで頭がクラクラしてしまいますよね。「XXE?」とか「SSRF?」なんて言われても、呪文のように聞こえるかもしれません。
でも、安心してください!今回は、この一見難しそうな「XXEを利用したSSRF攻撃」という、ちょっと恐ろしいサイバー攻撃の仕組みを、私たちの身近にある「家と郵便受け」の例えを使って、一歩ずつ優しく紐解いていきたいと思います。
難しい知識がなくても大丈夫です。一緒に仕組みを理解して、安全なシステムを作るための第一歩を踏み出しましょう!
—
1. 身近な例えで理解する「XML」と「XXE」
まずは、攻撃のターゲットになる「XML」という仕組みからお話しますね。
XMLってなんだっけ?
XMLとは、人間とコンピューターのどちらにとっても読みやすいように、データをタグ(目印)で囲んで整理するための書き方ルールです。例えば、お買い物の注文書をXMLで書くと、こんな感じになります。
<order>
<item>りんご</item>
<count>3</count>
</order>
<item>や<count>というタグが、データの「見出し」のような役割を果たしていますよね。
XXE(XML外部エンティティ攻撃)とは?
さて、XMLには「外部のファイルやネットワーク上のデータを読み込んで、こっそり合体させる」という便利な機能(外部エンティティ)があります。
これを例えるなら、「家の郵便受け(XMLパーサー)」です。
本来、郵便受けは「外から手紙を受け取るため」のものです。しかし、もしその郵便受けが「外から『隣の家の合鍵を取ってきて!』と書かれた指示(不正な外部エンティティ)」を真に受けて、勝手に実行してしまったらどうでしょうか?
これが XXE(XML External Entity) という脆弱性です。システムが信頼してはいけない外部からの指示を実行してしまうことで、サーバーの中身を覗き見られてしまうのです。
—
2. XXEを起点にした「SSRF攻撃」というコンボ技
今回のテーマである「XXEを利用したSSRF攻撃」は、先ほどのXXEを「ジャンプ台」にして、さらに奥のターゲットを攻撃するコンボ技です。
SSRF(サーバーサイドリクエストフォージェリー)ってなに?
SSRFを直訳すると「サーバー側での偽装リクエスト」となります。
これも身近な例えで考えてみましょう。
あなたは会社の受付にいます。そこに、怪しい人がやってきてこう言いました。
「すませーん、裏の金庫番の人に『私の代わりに中の様子を見てきて』って伝えてもらえますか?」
もし、受付(Webサーバー)がそのお願いを疑わずに、裏の金庫番(社内ネットワークのシステム)に頼みに行ってしまったら……?
裏の金庫番からすれば、「受付からの頼みなら安心だな」と思って、外からは絶対に見えないはずの金庫のデータ受付に渡しちゃいますよね。
これがSSRFです。「外からの指示を受けたサーバーを身代わりにして、普段は外からアクセスできない社内システムにこっそり侵入・偵察する攻撃」になります。
XXE + SSRF のコンボの流れ
この2つが合わさると、以下のような恐ろしい連係プレーが完成します。
1. 攻撃者が、悪意ある指示を書いたXMLデータをWebサーバーに送ります(XXEの発動)。
2. Webサーバーの郵便受けがその指示を読み込み、「よし、外部にアクセスしよう!」と勘違いします。
3. その指示の行き先を、社内ネットワークにある秘密の管理画面(通常は外から見えない)に向けさせます(SSRFの発動)。
4. Webサーバーが身代わりになって社内システムにアクセスし、その結果を攻撃者にこっそり持ち帰って見せびらかします。
「外からは入れない城の門」を、城の中の人(Webサーバー)に内側から開けさせちゃうようなイメージですね。
—
3. 実際のコードで見る脆弱な仕組み
新人開発者の方が「うっかり書いてしまいがち」な、危ないPHPプログラムの例を見てみましょう。
※実際の開発では、このような設定は絶対に避けてくださいね!
<?php
// 【危ない例】外部からのXML入力をそのまま信用して処理してしまうプログラム
// ユーザーから送信されたXMLデータを受け取る
$xmlData = file_get_contents('php://input');
// XMLを読み込むための準備(DOMDocumentを使用)
$dom = new DOMDocument();
// 【超危険!】外部エンティティの読み込みを禁止する設定(libxml_disable_entity_loader)を
// オフにしたままにしているため、XXE攻撃を受け入れてしまいます!
$dom->loadXML($xmlData, LIBXML_NOENT | LIBXML_DTDLOAD);
// XMLの中身を解析して画面に出力する
$result = $dom->saveXML();
echo "受信したデータ: " . $result;
?>
このコードの何がいけないかと言うと、loadXML 関数を使うときに、外部からの怪しい指示(Entity)を読み込む設定を野放しにしている点です。ここに攻撃者が <!ENTITY xxe SYSTEM "http://192.168.1.100/secret-data"> のようなXMLを送り込むと、サーバーは指定された社内IPにアクセスしてしまいます。
—
4. 一歩ずつ学ぶ!確実な防御対策
「うわ、怖いな……どうやって守ればいいんだろう?」と思いましたか?
安心してください。正しい対策を一つずつ設定すれば、この攻撃はしっかりと防ぐことができます!
対策1: XMLの外部読み込み機能をキッパリ「オフ」にする
一番確実なのは、PHPなどのプログラム側で「外部のデータは一切読み込みません!」と設定することです。
安全なコードの書き方を見てみましょう。
<?php
// 【安全な例】外部エンティティの読み込みを無効化する
// 1. 外部エンティティの読み込み機能を明示的にオフにする(これが一番大事!)
libxml_disable_entity_loader(true);
$xmlData = file_get_contents('php://input');
$dom = new DOMDocument();
// 2. 通常の安全なオプションだけでXMLを読み込む
$dom->loadXML($xmlData);
echo "安全に処理されました。";
?>
これだけで、郵便受けが怪しい指示(外部へのアクセスやファイル読み込み)を完全に無視してくれるようになります。「うちは外からの怪しい手紙は受け取りません!」と門番を厳しくするイメージですね。
対策2: セキュリティヘッダーやネットワークの設計を見直す
Webアプリケーションのプログラムだけでなく、インフラやネットワークの防犯も大切です。
- Webサーバーから外への無駄な通信を制限する(ファイヤーウォール)
Webサーバーが、必要のない社内ネットワークのサーバーや、変な外部IPへ勝手に通信できないようにルーターやファイアウォールでブロックしておきます。
- そもそもXMLを使う必要性を見直す
もし可能であれば、柔軟すぎるXMLではなく、もっとシンプルで安全な JSON 形式へ移行するのも現代のWeb開発では非常に有効な選択肢です。
—
まとめ
いかがでしたでしょうか?
「XXEを利用したSSRF攻撃」と聞くと、なんだか複雑で難しそうに感じますが、仕組みを紐解いてみると、
1. XXE = 郵便受けが外からの怪しい指示を勘違いして実行してしまうこと
2. SSRF = その勘違いを利用して、サーバーに身代わりで社内を偵察させること
という、例え話でスッキリと理解できたのではないでしょうか。
セキュリティ対策は、一度にすべてを完璧にする必要はありません。「外部のデータは安易に信用しない」「設定でしっかり機能を制限する」という基本を一つずつ丁寧に積み重ねていくことが、何よりも強力な防犯になります。
今日学んだ知識を、ぜひ明日からの開発や設計に役立ててみてくださいね。一歩ずつ、安全で強いシステムを作っていきましょう!
コメント