XML外部エンティティ(XXE)の深淵:パーサーの「善意」を悪用する攻撃アーキテクチャ
多くのエンジニアは、XMLを「枯れた技術」と見なし、レガシーなデータ交換フォーマットとして軽視している。しかし、その「枯れた」パーサーの内部には、設計上の原罪とも言える「外部リソースへの自動解決」という機能が眠っている。XXE(XML External Entity)攻撃は、単なる入力値の不備ではない。XMLパーサーという複雑なステートマシンが持つ、OSレベルのファイルシステムへのアクセス権限を悪用する、極めてプリミティブかつ致命的な権限昇格攻撃だ。
1. 攻撃者が狙う「パーサーの善意」という脆弱性
XMLの仕様(XML 1.0)には、DOCTYPE宣言内でENTITYを定義し、外部リソースを読み込む仕組みが存在する。これは本来、分散された文書の断片を結合するためのものだが、パーサーがセキュリティ制約なしにこれを処理すると、サーバー上の/etc/passwdやクラウド環境のメタデータAPI(http://169.254.169.254/)が丸裸になる。
攻撃者が狙うのは、パーサーが「外部リソースをフェッチする」という命令を実行する際の低レイヤ挙動だ。多くのパーサーは、URIスキーム(file://, http://, gopher://など)を解析し、バックエンドのネットワークスタックやファイルシステムAPIを呼び出す。この際、パーサー自体が実行ユーザー(多くの場合、Webサーバーの www-data や apache ユーザー)の権限を継承してしまう点が、インシデントの重大性を決定づける。
2. なぜ修正は後手に回るのか?
多くの開発者は、フレームワークが提供するデフォルト設定を盲信する。しかし、Javaの DocumentBuilderFactory やPHPの libxml は、歴史的な互換性を重視し、外部エンティティの解決をデフォルトで「有効」にしているケースが少なくない。
脆弱性を埋め込むのは、以下のような単純な処理だ。
// 脆弱な実装の例:外部エンティティを無効化していない
$doc = new DOMDocument();
$doc->loadXML($xml_input); // この時点で外部エンティティが解決されるリスクがある
攻撃者は、以下のようなペイロードを送り込むだけで、サーバーの心臓部を覗き見る。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
3. 鉄壁の防御:パーサー設定のハードニング
XXEを防ぐための唯一の絶対解は、パーサーの機能を「必要最小限に絞り込むこと」だ。現代的なアーキテクチャでは、XML自体を避けるのが最善だが、どうしても避けられない場合は、パーサーを完全に「ステートレスかつ孤立した状態」に設定しなければならない。
Java (DocumentBuilderFactory) での防御実装
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 外部エンティティの解決を完全に遮断する
String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);
// 外部パラメータエンティティも無効化
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
// DTD自体を完全に無視する設定
dbf.setExpandEntityReferences(false);
PHP (libxml) での防御実装
// libxmlのバージョンに応じて外部エンティティ読み込みを明示的にオフにする
libxml_set_external_entity_loader(function ($public, $system, $context) {
// 外部リソースへのアクセスを一切許可しない
return null;
});
// パーサー実行時にフラグを付与
$doc = new DOMDocument();
$doc->loadXML($xml_input, LIBXML_NONET | LIBXML_DTDLOAD | LIBXML_DTDATTR);
// ※注: LIBXML_DTDLOADを無効にするのが本質的
4. チーフホワイトハッカーの視点:次世代のセキュリティアーキテクチャ
XXEのような「入力を介したリソースアクセス」は、今後AIプロンプトインジェクションの防御にも通じる課題だ。LLMが外部ツールを呼び出す際、プロンプトに仕込まれた「偽の指示」が、パーサーが外部エンティティを解決する挙動と酷似している。
我々が今考えるべきは、以下のレイヤーでの防御だ。
- サンドボックス化(隔離): XMLパース処理を、メインアプリケーションとは別の、ネットワークアクセスが一切遮断された特権の低いコンテナで実行する。
- ガードレイルの実装: 入力値に対してスキーマバリデーション(XSD)を行い、
DOCTYPE宣言が含まれる入力を事前に拒否するゲートウェイを配置する。 - オブザーバビリティの強化: サーバーから外部への予期せぬアウトバウンド通信(DNSクエリやHTTPリクエスト)を、eBPFなどを用いてカーネルレベルで監視し、異常検知時にプロセスを即座にキルする。
XXEは、単なる設定ミスではない。これは、データが「コード(命令)」として解釈される可能性を持つ場所すべてに潜む、サイバーセキュリティの永遠のテーマである。パーサーの善意を信じるのではなく、その能力を徹底的に削ぎ落とすことこそが、攻撃者からシステムを守るための唯一の道だ。
コメント