XPathインジェクション:構造化データの「死角」を突く静かなる侵入者
多くのエンジニアは、SQLインジェクション(SQLi)の恐怖には慣れ親しんでいる。しかし、XPathインジェクションという言葉を聞いたとき、どれだけの者がその背後にある「XMLデータ構造そのものの脆弱性」を即座にイメージできるだろうか。
現代のエンタープライズアーキテクチャにおいて、XMLは依然としてレガシーシステムとの連携や、SAML認証、あるいは構成ファイル管理の要として深く根を張っている。XPathは、その複雑なツリー構造を縦横無尽に走査するための強力なクエリ言語だが、開発者が「文字列連結」という安易な実装に逃げた瞬間、それは攻撃者にとって最高の踏み台へと変貌する。
1. 低レイヤから見た「クエリ構造の崩壊」
XPathインジェクションの根本原因は、SQLiと同様に「データと命令の未分離」にある。しかし、SQLと決定的に異なるのは、XMLパーサーがクエリを解釈する際の「ノード走査の柔軟性」だ。
攻撃者は、' or '1'='1 のような単純な手法から、XMLの階層を自在に昇降するペイロードを送り込む。例えば、認証関数で使われるXPathクエリが以下のような文字列連結で行われている場合を想定してほしい。
// 危険な実装例:ユーザー入力をそのままXPath式に埋め込んでいる
string query = “/users/user[username='” + userInput + “‘ and password='” + passInput + “‘]/account/id”;
ここで攻撃者が admin' or '1'='1 を入力すると、クエリは /users/user[username='admin' or '1'='1' ... となり、常に真を返す。ここまでは古典的だが、真の脅威は「盲目的(Blind)な抽出」にある。count() 関数や string-length() 関数を駆使し、XMLのノード名や属性を1文字ずつ推測されるのだ。メモリ上でのクエリ変換プロセスを観察すると、パーサーが構文木(AST)を構築する段階で、悪意あるエスケープシーケンスがノードの参照先を意図的に誤認させているのがわかる。
2. アーキテクチャレベルでの防衛:パラメータ化の先にあるもの
「パラメータ化されたクエリを使え」という教条主義的なアドバイスは正しい。しかし、現実のシステムでは、既存のXPathライブラリがパラメータ化をサポートしていないケースも多い。その場合、我々アーキテクトが取るべきは「抽象化層の強制」だ。
Javaの javax.xml.xpath を使用する場合、XPathVariableResolver を実装し、動的な入力をクエリに直接含めるのではなく、変数としてバインドさせるのが正攻法である。
// 安全な実装例:変数を解決するリゾルバを定義する
public class MyVariableResolver implements XPathVariableResolver {
private final Map
public void setVariable(QName name, Object value) {
variables.put(name, value);
}
@Override
public Object resolveVariable(QName variableName) {
return variables.get(variableName);
}
}
// クエリ実行時
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setXPathVariableResolver(new MyVariableResolver());
// クエリ内では $variableName を使用し、直接的な文字列連結を排除する
XPathExpression expr = xpath.compile(“/users/user[username=$uname]/password”);
さらに踏み込むなら、XMLスキーマ(XSD)による厳しい入力バリデーションをゲートウェイで実装せよ。型定義に合致しないノード構造は、パーサーに渡る前に遮断されるべきだ。
3. 生成AI時代の新たな脅威:プロンプト注入との相乗効果
今、我々が直面しているのは、XMLを扱うLLMエージェントの脆弱性だ。生成AIがXML形式のプロンプトや出力命令を受け取る際、プロンプトインジェクションがXPathインジェクションを誘発するケースが増えている。
例えば、AIが自動生成したXPathクエリが、外部からの入力によって「特権昇格」を許すノードにアクセスするように誘導される事例だ。これに対するガードレイルとして、我々は「セマンティック・ファイアウォール」を設計する必要がある。
- 構造的制約の適用: AIが生成したクエリが、許可されたノード(ホワイトリスト)のみを走査しているか、実行前にサンドボックス環境で静的解析を行う。
- ゼロトラスト・パーシング: XMLパーサー自体をメモリ安全性の高いRustなどで実装されたモジュールに切り替え、バッファオーバーフローや外部エンティティ参照(XXE)の脆弱性を物理的に潰す。
結論:技術的負債への「意識的な介入」
XPathインジェクションは、一見すると「古臭い脆弱性」に見える。しかし、だからこそ油断が生まれる。多くのモダンなWebアプリでも、バックエンドのレガシーなインテグレーション層で、今なおこの穴が放置されている。
我々セキュリティアーキテクトに求められているのは、単なるパッチ適用ではない。アプリケーションのデータフロー全体を可視化し、「データがどこで解釈され、どこで命令になるか」という境界線を、冷徹なまでに明確に引き直すことだ。
XMLのツリー構造は、一度破壊されれば情報の機密性は崩壊する。技術の進歩に甘えず、足元のクエリ言語がどのように解釈されているのか、その泥臭いプロセスにこそ、我々が守るべき真実があることを忘れないでほしい。
コメント