XPathインジェクション:XMLの「裏口」を塞ぐ、現場の技術論
現場でコードをレビューしていると、SQLインジェクションには過敏なほど敏感なのに、XMLを扱う箇所になると途端にガードが甘くなるエンジニアが多い。XMLデータベースや設定ファイルの読み込みにXPathを使っている君たち、そのクエリは本当に安全か?
今日は、XPathインジェクションという「盲点」について話そう。これは単なる古い脆弱性ではない。今もなお、レガシーなシステムや構成管理の裏側で、攻撃者が虎視眈々と狙っている攻撃手法だ。
1. XPathインジェクションの何が怖いのか
XPathインジェクションは、SQLインジェクションのXML版だ。ユーザーからの入力値がクエリ文字列に直接結合されることで、本来意図しないノードへアクセスされたり、認証をバイパスされたりする。
例えば、ユーザー名とパスワードをXMLから検証するようなコードで、入力値に ' or '1'='1 のような文字列を注入されるとどうなるか。クエリ全体が評価され、最初のユーザー(多くの場合管理者)の認証が突破されてしまう。
攻撃のPoC(概念実証):
悪意あるユーザーがログインフォームのユーザー名欄に以下を入力したとしよう。
admin' or '1'='1
クエリが次のように解釈されてしまう。
//user[username/text()='admin' or '1'='1' and password/text()='...']
これだけで、パスワードを無視してadminとしてログインが完了する。これがXPathインジェクションの恐ろしさだ。
2. 「サニタイズ」という幻想を捨てろ
よく「シングルクォートをエスケープすればいい」と言うエンジニアがいるが、それは根本的な解決にならない。攻撃者はXPath関数の仕様を悪用し、concat() 関数や substring() を使って、メタ文字を回避しながらデータ構造をバラしていく。
正しい防御の鉄則は、「クエリとデータを分離すること」だ。
SQLにおけるプリペアドステートメントと同じように、XPathでも「変数のバインド」を行うのが唯一の正解だ。
3. 実装サンプル:Pythonによるセキュアな実装
Pythonの lxml ライブラリを使用する場合、xpath() メソッドの variables 引数を使うことで、入力値をクエリから完全に切り離すことができる。これが安全な開発の「標準」だ。
from lxml import etree
安全な実装例
def get_user_data(username, password):
xml_data = “””
root = etree.fromstring(xml_data)
# 外部からの入力値を直接結合せず、変数としてバインドする
# $user_val という変数を使うことで、インジェクションを物理的に不可能にする
query = “//user[username=$user_val and password=$pass_val]”
# 検索実行
results = root.xpath(query, user_val=username, pass_val=password)
return len(results) > 0
悪意ある入力値でも、単なる文字列として処理されるため安全
print(get_user_data(“admin’ or ‘1’=’1”, “any”)) # 結果: False (安全!)
4. PHP(DOMXPath)での対策:型変換とホワイトリスト
PHPの DOMXPath は標準で変数バインドをサポートしていない。そのため、さらに泥臭い防御が必要だ。
1. ホワイトリストの徹底: 入力値が期待する形式(英数字のみ等)か厳格にチェックする。
2. 型変換: 数値であれば (int) にキャストする。
3. エスケープの二重防衛: どうしても文字列を使う場合は、XPathの仕様に基づきシングルクォートとダブルクォートを適切に処理するクラスを挟む。
// PHPでの対策例
$xpath = new DOMXPath($dom);
// ユーザー入力
$username = $_POST[‘username’];
// 1. 入力値の検証(英数字以外は弾く)
if (!preg_match(‘/^[a-zA-Z0-9]+$/’, $username)) {
die(“不正な入力値です”);
}
// 2. クエリ構築(ホワイトリストを通った安全な値のみを使用)
$query = sprintf(“//user[username=’%s’]”, $username);
$result = $xpath->query($query);
5. 最後に:インフラ層での防御(WAFの活用)
コードレベルの修正が最優先だが、多層防御としてWAFの活用も忘れないでほしい。AWS WAFを使用しているなら、AWSManagedRulesCommonRuleSet を有効にすることで、XPathインジェクションのシグネチャを検知できる。
また、Nginxで特定のパスへのXML入力を制限する設定も有効だ。
Nginx設定例:特定のXML解析エンドポイントへの制限
location /api/v1/xml-process {
# SQL/XPathインジェクションの兆候があるリクエストをブロック
if ($query_string ~ “(‘|–|or|and|substring|concat)”) {
return 403;
}
proxy_pass http://backend_app;
}
まとめ
XPathインジェクション対策の肝は、「入力を信用せず、構造を分離する」こと。
「動けばいい」というコードは、数年後の自分やチームを苦しめる技術的負債であり、セキュリティホールだ。
今日から君たちのプロジェクトで、XPathを使用している箇所を検索してほしい。もし文字列結合でクエリを作っている箇所があれば、即座に変数バインドへ修正するんだ。それが、我々エンジニアが守るべき「信頼」の積み重ねなのだから。
コメント