「うちはSQLデータベースじゃなくてXMLファイルで管理しているから、インジェクション攻撃は関係ない」と思っていませんか?残念ながら、それは危険な思い込みです。
XML専用のクエリ言語「XPath」を悪用するXPathインジェクションという攻撃手法があります。仕組みはSQLインジェクションと同じでありながら、セキュリティチェックで見落とされやすく、認証回避からXML文書全体のデータ盗み出しまで深刻な被害を引き起こします。
この記事では、XPathインジェクションの仕組み・実際の攻撃手口・PHPやPythonでの具体的な防御方法まで、現場で使えるレベルで解説します。

XPathとは?まず基本を押さえておこう
XPath(XML Path Language)は、XML文書の中から特定のデータを検索・取得するためのクエリ言語です。SQLがリレーショナルデータベースに問い合わせるのと同様に、XPathはXML文書のツリー構造に対して問い合わせを行います。
たとえば、次のようなXML形式のユーザー管理ファイルがあるとします。
<?xml version="1.0"?> <users> <user> <username>admin</username> <password>s3cur3p4ss</password> <role>administrator</role> </user> <user> <username>tanaka</username> <password>pass1234</password> <role>user</role> </user> </users>
このXMLから「usernameが’tanaka’のユーザー」を取得するXPathクエリは、次のように書きます。
//user[username='tanaka']
Webアプリケーションはログインフォームのユーザー入力をこのXPathクエリに組み込んで認証処理を行います。ここに「入力値を検証せずそのまま組み込む」という実装上の欠陥があると、XPathインジェクションが成立します。
XPathインジェクションの仕組み:攻撃者はどう悪用するか
1. 脆弱な実装コードの例
PHPで書かれた脆弱なログイン処理を見てみましょう。ユーザーが入力した値をそのままXPathクエリ文字列に連結しています。
<?php # 脆弱な実装例(PHP) $username = $_POST['username']; $password = $_POST['password']; # ユーザー入力をそのままXPathクエリに連結している(危険) $query = "//user[username='" . $username . "' and password='" . $password . "']"; $xml = simplexml_load_file('users.xml'); $result = $xml->xpath($query); if ($result) { // ログイン成功処理 echo "ログインしました"; } ?>
正規のログインでは、クエリはこうなります。
# ユーザー名: tanaka、パスワード: pass1234 を入力した場合 //user[username='tanaka' and password='pass1234']
2. 認証回避攻撃(最も典型的な手口)
攻撃者がユーザー名フィールドに次の文字列を入力するとどうなるでしょうか。
# 攻撃者の入力 ユーザー名: ' or '1'='1 パスワード: anything
生成されるXPathクエリはこのように変形されます。
//user[username='' or '1'='1' and password='anything']
'1'='1' は常に真(True)なので、パスワードを一切知らなくても、XML内の最初のユーザー(多くの場合、管理者アカウント)としてログインできてしまいます。SQLインジェクションの OR 1=1 と全く同じ原理です。
3. ブラインドXPathインジェクション:データを1文字ずつ盗み出す
さらに高度な攻撃として「ブラインドXPathインジェクション」があります。アプリケーションが直接データを返さない場合でも、ログイン成功・失敗という2値の応答だけを手がかりに、XML文書の内容を1文字ずつ推測して盗み出せます。
# 管理者パスワードの1文字目が 'a' かどうかを確認するクエリ ' or substring(//user[1]/password,1,1)='a # 1文字目が 's' かどうかを確認するクエリ ' or substring(//user[1]/password,1,1)='s # 2文字目の確認 ' or substring(//user[1]/password,2,1)='3
「ログイン成功(一致)」「ログイン失敗(不一致)」の応答パターンを繰り返しチェックすることで、自動化ツールを使えば数分でパスワードの全文字を特定できます。明示的なエラーメッセージがなくても攻撃が成立する点が、この手口の厄介なところです。
どんなシステムが標的になるのか
XPathインジェクションが成立するには、次の条件が揃っている必要があります。
・バックエンドにXMLデータベース(eXist-db等)またはXMLファイルをデータストアとして使用している
・Webアプリケーションがユーザー入力をXPathクエリに直接組み込んでいる
・入力のバリデーション・エスケープが行われていない
具体的にはこのようなシステムで発見されることがあります。
・レガシーな社内システム: XMLファイルでユーザー情報や設定を管理している古いWebアプリケーション
・SOAP/XML Webサービス: XMLベースのAPIリクエストをバックエンドで処理するシステム
・eコマースシステム: 商品カタログや在庫データをXML形式で保存しているシステム
・設定管理ポータル: XMLで設定ファイルを管理し、Web画面から検索・閲覧できるツール
・レポートエンジン: XMLデータを元にレポートを生成するシステム
「SQLデータベースを使っていないからインジェクション攻撃は関係ない」という認識は危険です。なお、XMLを処理するシステムにはXXE(XML外部エンティティ攻撃)という別の脆弱性も潜んでいることが多く、XPathインジェクションと必ずセットで点検することを強く推奨します。
具体的な防御手順
1. パラメータ化XPathクエリの利用(最優先)
SQLインジェクション対策でのプリペアドステートメントと同じ考え方です。ユーザー入力をクエリ文字列に直接連結せず、変数として渡す「パラメータ化クエリ」を使います。JavaのSaxon APIなど一部のライブラリがこれをサポートしています。
# Java(Saxon API)でのパラメータ化XPath例 XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); # ユーザー入力を変数として渡す(安全な実装) xpath.setXPathVariableResolver(variableName -> { if ("username".equals(variableName.getLocalPart())) return userInput_username; if ("password".equals(variableName.getLocalPart())) return userInput_password; return null; }); # $username と $password に入力値が束縛される(文字列連結しない) XPathExpression expr = xpath.compile( "//user[username=$username and password=$password]" ); NodeList result = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
残念ながら、PHPのSimpleXMLやDOMXPathにはパラメータ化の組み込みサポートがなく、次に説明するホワイトリスト検証とエスケープで代替する必要があります。
2. 入力値のホワイトリスト検証
ユーザー名・パスワードなど、入力に含まれるべき文字を厳密に制限します。英数字以外の特殊文字が含まれていれば即座に拒否します。
# Python:ユーザー名に英数字・アンダースコア・ハイフンのみ許可 import re def validate_username(username): # 1文字以上64文字以下、英数字・アンダースコア・ハイフンのみ if not re.match(r'^[a-zA-Z0-9_\-]{1,64}$', username): raise ValueError("不正なユーザー名が入力されました") return username def validate_input(value): # XPathで特別な意味を持つ文字を完全に拒否する forbidden_chars = ["'", '"', '[', ']', '/', '@', '*', '(', ')', '=', '|', '+', '-', ',', ';', ':'] for char in forbidden_chars: if char in value: raise ValueError(f"不正な文字が含まれています: {char}") return value
XPathクエリで特別な意味を持つ文字は必ず拒否またはエスケープします。
・シングルクォート(’): 文字列の区切り文字として使われ、クエリ改ざんの主要な手段
・ダブルクォート(”): 文字列の代替区切り文字
・角括弧([ ]): XPathの述語(条件式)の区切り
・スラッシュ: XPathのパス区切り文字(子要素の参照)
・アットマーク(@): 属性の指定に使用
・アスタリスク(*): 任意の要素にマッチするワイルドカード
3. エラーメッセージの抑制
XPath構文エラーや実行エラーの詳細をユーザーに表示すると、XML文書の構造や利用しているXPathライブラリを攻撃者に教えてしまいます。本番環境では詳細なエラーを非表示にし、内部ログにのみ記録します。
# PHP:本番環境でのエラーメッセージ非表示設定 # php.ini または .htaccess で設定する # エラーをブラウザに表示しない(デフォルト変更点) display_errors = Off # エラーをログに記録する(デフォルト変更点) log_errors = On error_log = /var/log/php/error.log
4. XMLデータベースのアクセス権限を最小化
アプリケーションがXMLデータベースに接続するアカウントに、必要最小限の権限だけを付与します。特定のコレクション(テーブル相当)への読み取りのみに限定するだけでも、攻撃が成功した際の被害範囲を大幅に抑えられます。管理者権限でデータベースに接続していれば、攻撃者が取得できるデータの範囲がXML文書全体に及びます。
5. WAFによる補完的防御
WAF(Webアプリケーションファイアウォール)を利用している場合、XPathインジェクションに対応したシグネチャを有効にします。これにより既知の攻撃パターンをリクエスト段階でブロックできます。ただし、WAFはコード修正の代替ではありません。コード側の根本的な対策を実施した上でWAFを補完として活用します。
中小企業でも今日からできること
開発リソースが限られる環境でも、次の手順で即座にリスクを評価・低減できます。
・XMLを使った機能の棚卸し: 自社システムでXMLファイルやXMLデータベースを使っている認証・検索機能を一覧化する
・文字列連結箇所の検索: コードベースで xpath( や .xpath( に続いてユーザー入力が直接連結されている箇所をgrepで探す
・入力バリデーションの追加: ユーザー入力を受け付ける全フォームに、英数字以外の特殊文字を拒否するチェックを追加する
・脆弱性スキャンの実施: OWASP ZAP等の無料ツールで既存のWebアプリに対してXPathインジェクションのスキャンを試みる
・エラーメッセージの確認: ログインフォームなどに意図的に特殊文字(例: ')を入力し、XPath関連のエラーがブラウザに表示されていないかを確認する
・XXEとのセット点検: XMLを処理するシステムはXPathインジェクションと同時にXXEも点検する
OWASP Top 10 ではインジェクション全般が主要リスクとして挙げられており、XPathインジェクションもその範囲に含まれます。OWASP Top 10の各項目を定期的に自社システムに照らし合わせる取り組みも効果的です。
また、XMLを処理するWebサーバー自体のセキュリティ強化については、姉妹サイトLinuxMaster.JPでLinuxサーバーのハードニング手順を詳しく解説しています。
よくある誤解と注意点
【誤解1】「XMLデータベースなんて使っていないから関係ない」
設定ファイルの読み込み・SOAP APIのバックエンド・レポートエンジンなど、明示的にXMLデータベースを採用していなくてもXMLを処理しているシステムは意外と多くあります。「XMLデータベースを使っている認識がない」という状況こそ、棚卸しが最も必要な場面です。
【誤解2】「SQLインジェクション対策をしていれば安全」
SQLインジェクション対策とXPathインジェクション対策は別物です。SQLのプリペアドステートメントやエスケープ関数は、XPathクエリの安全化には一切効果がありません。使用しているクエリ言語ごとに対応した対策が必要です。
【誤解3】「SQLインジェクションと比べて被害が小さい」
XML文書全体が平文で格納されている場合、攻撃が成功するとシステム内のすべてのXMLデータが漏洩する可能性があります。パスワード・APIキー・個人情報を含むXMLであれば、被害規模はSQLインジェクションと同等以上になりえます。重要度を低く見積もらないことが重要です。
【注意】XXE(XML外部エンティティ攻撃)とのセット対策が必須
XPathインジェクションが成立するシステムでは、多くの場合XXE(XML外部エンティティ攻撃)も潜在的に脆弱です。XXEはXMLパーサーの外部エンティティ展開機能を悪用してサーバー内のファイルを読み取る攻撃で、XPathインジェクションと組み合わせて使われることもあります。必ず両方を点検してください。なお、法律に関わる事項(不正アクセス禁止法への対応等)については法律の専門家にご確認ください。

本記事のまとめ
| 攻撃手法 | 仕組み | 主な被害 |
|---|---|---|
| 認証回避 | ‘ or ‘1’=’1 形式の入力でXPathクエリを改ざん | 管理者権限での不正ログイン |
| ブラインドインジェクション | 応答の差異でXML内データを1文字ずつ推測 | パスワード・APIキー・個人情報の漏洩 |
| 対策 | 効果 | 難易度 |
|---|---|---|
| パラメータ化XPathクエリ | 注入を根本的に防止 | 中(ライブラリ対応が必要) |
| ホワイトリスト入力検証 | 特殊文字を含む不正入力を拒否 | 低(バリデーション追加) |
| エラーメッセージ抑制 | XML構造の推測を困難にする | 低(設定変更のみ) |
| アクセス権限の最小化 | 攻撃成功時の被害範囲を限定 | 低(権限設定の見直し) |
| WAFによる補完 | 既知パターンをリクエスト段階でブロック | 低(シグネチャ有効化) |
XPathインジェクションは、SQLインジェクションと同じ原理でありながら、セキュリティ対策の死角になりやすい脆弱性です。「SQLインジェクションは対策済み」「XMLデータベースは使っていない」という認識があっても、XMLを処理しているシステムが存在する場合は別途点検が必要です。
システム棚卸し → 文字列連結箇所のコードレビュー → 入力バリデーション追加という手順で、今日から対策を始めてみてください。
PR
体系的に学ぶ 安全なWebアプリケーションの作り方 第2版(徳丸浩/SBクリエイティブ)
XPathインジェクションを含むWebアプリケーションのさまざまな脆弱性を体系的に解説した定番書。SQLインジェクション・XSS・CSRFなど主要攻撃手法の原因と対策を、実際のコード例で丁寧に学べます。セキュリティ担当者・開発者の必読書です。
