【入門編】 XML外部エンティティ(XXE)攻撃による機密ファイル読み取り – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!システム開発の現場に飛び込んだばかりの新人の皆さん、毎日の業務でお忙しい中、セキュリティの勉強も本当にお疲れ様です。

「セキュリティってなんだか難しそう…」
「専門用語が多くて、どこから手をつけていいか分からない…」

そんな不安を抱えていませんか?大丈夫です。今回は、Webアプリの裏側でこっそり起こるちょっと怖い攻撃「XXE(XML外部エンティティ)攻撃」について、身近な「お家の防犯」に例えながら、一歩ずつ優しく紐解いていきたいと思います。

今日このブログを読み終える頃には、攻撃の仕組みがスッキリと理解でき、明日から使える安全なコードの書き方までバッチリ身についちゃいますよ!それでは、さっそく見ていきましょう!

—

1. 家の鍵に例えて理解する「XML」と「XXE攻撃」の正体

まずは、今回の主役である「XML」と、それが引き起こす「XXE攻撃」を、私たちの身近な生活に置き換えて考えてみましょう。

XMLってなんだろう?

システムの世界では、さまざまなプログラム同士がデータをやり取りするために、共通の「言葉」を使います。その言葉の一つがXMLです。
例えば、ユーザーからの注文データや設定ファイルを、プログラムが読みやすいように綺麗に整理した「書類のフォーマット」だと思ってください。

泥棒が入ってくる「魔法の合言葉」:XXE攻撃

通常、このXMLという書類には、注文した商品の名前や数量が書かれているはずです。しかし、もし攻撃者が「この書類の中に、別の指示をこっそり混ぜておいたらどうなるだろう?」と企んだら……?

これがXXE(XML External Entity)攻撃の基本です。
イメージとしては、「郵便受けに『家の中にある金庫の鍵の場所を教えて』と書いた手紙を放り込み、郵便受けの裏側でそれを自動的に読んでしまう自動返信装置が待ち構えていた」ような状態です。

XMLのパーサー(書類を読み取る係のプログラム)が「おや、外部のファイルを読み込めって書いてあるな。親切だから取ってきてあげよう!」と、サーバーの奥深くにある秘密のファイル(パスワードが書かれたファイルなど)を勝手に読み込み、攻撃者に渡しちゃうんですね。恐ろしいことに、本来は見ちゃいけないはずのファイルが、丸見えになってしまうのです。

—

2. 実際の攻撃はどうやって行われるの?(仕組みの裏側)

もう少し具体的に、システムの中で何が起きているのかを覗いてみましょう。

脆弱性のあるプログラムは、受け取ったXMLをそのまま信用して処理してしまいます。攻撃者はここに、次のような細工をしたXMLを送り込みます。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
  <!-- 外部のファイルを読み込むように指定する(ここが罠!) -->
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
  <name>&xxe;</name>
</root>

このXMLの中では、<!ENTITY>という機能を使って、「&xxe;という目印が使われたら、サーバーの /etc/passwd(Linuxのユーザー情報が書かれたファイル)の中身と置き換えてね」と指示しています。

パーサーがこの指示に従ってしまうと、サーバーの機密ファイルが外部に流出してしまうというわけです。新人の皆さんも、「プログラムは何でもかんでも言われた通りに信じ込んじゃいけないんだな」ということがイメージできたのではないでしょうか?

—

3. 「じゃあ、どうやって防ぐの?」安全な実装のコツ

「うわぁ、怖い攻撃ですね……。どうすれば防げるんですか?」
安心してください!ちゃんと強力な対策が用意されています。

防犯に例えるなら、「郵便受けに自動返信装置なんていう危ない機能はそもそも取り付けない(無効化する)」、これが一番の解決策です。

プログラムがXMLを読み込むとき(パースするとき)に、「外部のファイルを勝手に読み込む機能(外部エンティティの解決)」をきっぱりと禁止(オフ)に設定すればいいのです。

PHPでの安全な実装コード例

それでは、実際の開発現場でよく使われるPHPを例に、安全なコードの書き方を見てみましょう。設定一つで、セキュリティは見違えるほど強くなりますよ!

<?php
// 【重要】LIBXML_NOENTフラグを使わない、または外部エンティティを無効化する設定を行います。
// 最近のPHPの標準設定ではデフォルトでオフになっていますが、明示的に安全な設定をすることがプロの技です。

// 内部的なXMLの実体参照(エンティティ)の読み込みを無効化する設定
libxml_disable_entity_loader(true);

// ユーザーからの入力を受け取る(例としてPOSTされたXMLデータとします)
$xmlData = file_get_contents('php://input');

// XMLを安全に読み込むための設定(外部実体のロードを確実に防ぎます)
$dom = new DOMDocument();

// 外部エンティティの読み込みを禁止するフラグを有効にする
$dom->loadXML($xmlData, LIBXML_NONET);

// 安全にパースされたデータを使って処理を続行...
echo "XMLの処理が安全に完了しました。";
?>

コードのポイント解説

  • libxml_disable_entity_loader(true); : 外部エンティティの読み込み機能を全体的にストップさせる呪文です。まずはこれを覚えておきましょう!
  • LIBXML_NONET : ネットワークを通じた外部リソースへのアクセスを一切禁止するフラグです。これをつけておけば、仮に怪しいXMLが来ても「ネットワーク?ダメです!」とパーサーが突っ返してくれます。

—

まとめ:一歩ずつ、確実なセキュリティ対策を

今回は、XXE攻撃の仕組みから、身近な例え、そして具体的な防御コードまで一気に解説してきましたが、いかがでしたでしょうか?

  • XMLは便利な反面、外部ファイルを読み込む危ない機能(エンティティ)を持っている
  • 攻撃者はその機能を悪用して、サーバーの機密ファイルを盗み見ようとする
  • 対策はシンプル。パーサーの設定で「外部読み込みを禁止(オフ)」にするだけ!

セキュリティの対策と聞くと身構えてしまうかもしれませんが、仕組みを知り、正しい設定を一つずつ覚えていけば、必ず安全なシステムを作ることができます。

焦らず、一歩ずつ、頼りになるエンジニアへの階段を登っていきましょう!次回の解説もお楽しみに!

コメント

タイトルとURLをコピーしました