こんにちは!新人IT担当者や、これからセキュリティの勉強を始める開発者の皆さん、日々の業務お疲れ様です。
システムを作ったり運用したりしていると、「セキュリティ」という言葉を毎日のように耳にしますよね。ファイアウォールとか、パスワードのハッシュ化とか、なんだか難しそうな話がいっぱいあって、頭がパンクしそうになっていませんか?
今回は、その中でも特に初心者泣かせな名前の攻撃、「XXE(XML External Entity)攻撃」についてお話しします。名前はめちゃくちゃ難しそうですが、要するに「プログラムが勝手に外のファイルを読みに行ってしまうお留守番の隙」のことです。
身近な例えを交えながら、一歩ずつ分かりやすく解説していきますので、リラックスして読んでいってくださいね!
—
1. 家の鍵に例える「XML」と「外部エンティティ」のお話
まずは、今回の主役である「XML」という仕組みを、身近なものに例えてみましょう。
皆さんの家に、荷物が届いたときのことを想像してください。ダンボール箱の中身がバラバラにならないように、「これは本です」「これは服です」と綺麗に仕分けして、外側に伝票が貼ってありますよね。
ITの世界で、この「綺麗にデータを仕分けして包む箱」の役割をするのが XML というデータ形式です。
そして、XMLにはちょっと便利な機能があります。それが 「外部エンティティ(DTD)」 です。これは例えるなら、「手紙の中に『詳しくはあそこの本棚の3ページ目を見てね』と書いておく機能」です。
通常、これは同じ建物の中にある資料を見るだけなので便利なのですが、もし「悪い泥棒」がやってきて、この手紙の仕組みを悪用したらどうなるでしょうか?
—
2. 泥棒はどうやってシステムをハックするのか?(XXE攻撃の仕組み)
攻撃者(泥棒)は、システムに対してわざと細工をしたXMLデータを送りつけます。
通常のデータなら「氏名:山田」「年齢:25」と書いてあるところに、泥棒は次のような細工を仕込みます。
> 「ねえ、このプログラムさん、私の代わりにサーバーの中にある大事なファイル(例えばパスワードが書いてあるファイルなど)を読み込んで、この画面に表示してよ!」
もし、システムの「XMLパーサー(XMLのデータを読み解く係のシステム)」が、このお願いを素直に聞いてしまうとどうなるでしょうか?
係の人は「わかりました!」と言って、サーバーの奥深くにある機密ファイルを勝手に読み込み、攻撃者にペロッと見せてしまうのです。これが XXE(XML External Entity)攻撃 の正体です。
外からやってきた怪しいお願い(外部エンティティ)を、プログラムがそのまま信じて実行してしまうことが原因なんですね。
—
3. 実際にコードを見てみよう(危ないPHPの例)
百聞は一見に如かず。実際に、どんなコードがこの脆弱性(隙)を生んでしまうのか、PHPというプログラミング言語を例に見てみましょう。
以下のコードは、受け取ったXMLデータを何も考えずにそのまま読み込んでいる危険な例です。
<?php
// 【危険な例】外部からのXML入力をそのままパース(解析)するコード
$xmlData = file_get_contents('php://input');
// DOMDocumentを使ってXMLを読み込む
$dom = new DOMDocument();
// ここがポイント:デフォルトの設定のままだと外部のファイル読み込みを許してしまいます!
$dom->loadXML($xmlData, LIBXML_NOENT);
// XMLの中身を処理するロジック(省略)
echo "XMLの処理が完了しました。";
?>
このコードの何がいけないか分かりますか?
loadXML() という関数を使っていますが、セキュリティ対策を何もしていないため、受け取ったXMLの中に「外のファイルを読んで!」という指示(外部エンティティ)が含まれていると、それを実行してしまうのです。
—
4. パーサーをセキュアに設定しよう(具体的な防御策)
「じゃあ、どうやって防げばいいの?」という話ですよね。安心してください。対策はとてもシンプルです。
XMLを読む係の人(パーサー)に対して、「外のファイルやネットワークを勝手に覗き見しちゃダメ!」というルール(設定)を厳しく教えてあげればいいのです。
先ほどのPHPのコードを、安全な設定(セキュア設定)に書き換えてみましょう。
<?php
// 【安全な例】外部エンティティの読み込みを禁止したセキュアなコード
$xmlData = file_get_contents('php://input');
$dom = new DOMDocument();
// ★ここが超重要:外部外部DTDのロードを無効化する設定(LIBXML_DTDLOAD)をオフにする
// さらに、外部エンティティの展開を無効化するためにlibxmlの設定を変更します。
// libxmlの機能を安全にコントロールするための呪文のようなものです
$libxml_disable_entity_loader = true;
if (function_exists('libxml_disable_entity_loader')) {
// 古いPHPバージョン向けの外部エンティティ無効化
@libxml_disable_entity_loader(true);
}
// 外部エンティティの参照を完全に遮断してXMLを安全に読み込む
$dom->loadXML($xmlData, LIBXML_DTDLOAD | LIBXML_DTDVALID);
// ※注意: PHP 8.0以降では libxml_disable_entity_loader は非推奨(デフォルトで安全)になっていますが、
// パーサーライブラリごとの正確な安全フラグを有効にすることが大切です。
echo "安全にXMLを処理しました。";
?>
ポイントは、「外部のDTD(文書型定義)や外部エンティティの処理を明示的にオフ(無効化)にする」ということです。これだけで、泥棒がいくら「あのファイルを読んで!」とお願いしても、プログラムは「無視!」と突っぱねてくれるようになります。
—
5. まとめ:一歩ずつ、安全な開発を心がけよう!
今回は、XXE攻撃の仕組みと、XMLパーサーのセキュア設定についてお話ししました。最後に今日のポイントを振り返ってみましょう。
1. XXE攻撃とは?
- XMLの「外部エンティティ」という機能の隙を突いて、サーバー内の機密ファイルを盗み出す攻撃のこと。
2. なぜ起こる?
- プログラム(XMLパーサー)が、外部からの怪しい「ファイルの読み込みおねがい」を素直に聞いてしまうから。
3. どうやって防ぐ?
- パーサーの設定で「外部エンティティの処理やDTDの読み込み」をしっかりと無効化(オフ)にする。
セキュリティの対策と聞くと身構えてしまいますが、要は「プログラムに余計な我慢をさせず、ルールをきっちり決めてあげること」です。
日々のコーディングや設定の見直しの際に、「このパーサー、外を勝手に覗き見しない設定になっているかな?」と少しだけ気に留めてみてくださいね。
皆さんのシステムが、安全で頑丈な要塞になるよう、これからも一歩ずつ一緒に学んでいきましょう!
コメント