概要
関連ゼイジャッキー
XPathインジェクション
XMLの海に潜むアカエイのような姿をしたゼイジャッキー。
不用意に釣り上げると、しっぽに潜ませた注射器で毒を注入してくる。
険しいXMLの海で揉まれた傷がからだ中にある。
ゼイジャッキーとは?
XPathインジェクションとは
XMLデータに対して、ユーザが制御可能な値を用いてXPathを生成する場合に発生する脆弱性です。
これにより、開発者の意図しないXPathが発行され、アプリケーションロジックを変更されてしまう可能性があります。
XPathインジェクションが発生する可能性のあるアプリケーションとして、次のようなものが考えられます。
- XML DBのように、XMLファイルそのものをデータベースとして扱い、言語やフレームワークが保有する機能を使ってXPathによる問い合わせをするケース
- XMLデータをDBMS(MySQLやPostgreSQLなど)に格納し、DBMSが保有する機能を使ってXPathによる問い合わせをするケース
アプリケーション内でXPathがどのような役割を担っているかによって影響は異なりますが、たとえば次のような被害が想定されます。
- 外部に公開したくないXML上の情報が漏洩する
- サーバ上のリモートファイルにアクセスされる
- XMLに記載された情報をもとにユーザ認証をする場合、これをバイパスされ不正にログインされる
- 攻撃者が用意した細工されたURLにアクセスしたユーザが、意図しないコンテンツを閲覧、または意図しない操作をさせられる可能性がある
- (DBMS上に格納されたXMLデータに対して、XPath式を含んで問い合わせる場合)SQLインジェクション攻撃の足掛かりになる可能性がある
SQLインジェクションの脆弱性に関する内容についてはここでは割愛しますが、鋭意執筆中ですので公開までお待ちください。
XPathとは
XPath(XML Path Language)は、XML形式のドキュメントに対して、参照、操作するためのクエリ言語です。
本記事中では、XML DBに対する問い合わせを目的としてXPathを用いていますが、昨今のトレンドに照らし合わせるとウェブスクレイピングにおいても目にする機会は多いと思います。
例として、次のようなXMLに対してXPathがどのように機能するかを考えてみます。
<?xml version="1.0" encoding="UTF-8" ?>
<users>
<user role="admin">
<name>admin</name>
<password>admin_password</password>
</user>
<user role="guest">
<name>user1</name>
<password>password1</password>
</user>
<user role="guest">
<name>user2</name>
<password>password2</password>
</user>
</users>
このXMLの構造は、ツリー構造として、次のように表現できます。
XPathは、図のような階層構造を表現したような構文で記述され、任意の要素を柔軟に表現できます。
次の図は、先ほどのXMLに対して、対応するXPathの例を記載したものです。
XPathインジェクションの仕組み
ここまででXPathおよびXPathインジェクションの概要について触れました。ここからは実際のコードと図を用いて、XPathインジェクションの仕組みについて解説していきます。
例として、ログイン処理にXPathおよびXMLを扱うアプリケーションを想定します。
ユーザ入力値として受け取ったユーザ名とパスワードからXPathを生成し、生成されたXPathでXMLに対して問い合わせています。問い合わせた結果、XPathに一致するXML要素が存在していた場合、ログインに成功します。
このアプリケーションでは、XPathを生成する処理はユーザ入力値の検証をせず、文字列結合を使って実装されています。
次の例はJavaにおける実装例です。
String expression = "/users/user[name/text() = '" + username + ' and password/text() = ' + password + "']";
username
、password
は、フォームから受け取ったユーザ入力値です。
この場合、XPathインジェクションの脆弱性が存在します。
攻撃例
簡単な攻撃方法として、攻撃者が次のようなユーザ名とパスワードを入力したとします。
- username:
' or '1' = '1
- password:
' or '1' = '1
このとき、XPathは次のように構築、評価されます。
ユーザ名・パスワードとして入力された' or '1' = '1
は、XMLに記載された情報とは一致しませんが、アプリケーションが評価するXPathは次のようになります。
/users/user[name/text() = '' or '1' = '1' and password/text() = '' or '1' = '1']
本来意図していたXPathの意味と異なっていることがわかります。日本語にして考えると、次のように表現できます。
- user要素内の
- name要素のテキストが
- 空白である
- または'1' = '1'
である
- かつ、password要素のテキストが
- 空白である
- または'1' = '1'
である
そのためこの実装では、XPathインジェクションに対して脆弱であることがわかります。
JVN iPediaに登録された本脆弱性の件数
本記事で取り扱ったXPathインジェクションは、より包括的なカテゴリとしてXMLインジェクション(ブラインドXPathインジェクション)(CWE-91)が該当します。
次の表は直近10年間で、CWE-91に該当する脆弱性として報告され、JVNに登録された件数です。
年代 | 件数 |
2013 | 2件 |
2014 | 1件 |
2015 | 3件 |
2016 | 2件 |
2017 | 4件 |
2018 | 6件 |
2019 | 1件 |
2020 | 8件 |
2021 | 1件 |
2022 |
1件 |
XPathインジェクションの脆弱性があるとして報告される件数は比較的少ないですが、実際に悪用された場合の影響は大きくなるため、適切な対策が必要です。
対策方法
SQLインジェクション同様、XPathインジェクションにおいてもプレースホルダによる対策が有効です。
ここでは、冒頭で扱った脆弱なログイン機能を模したアプリケーションを、プレースホルダを用いて対策する方法を紹介します。
次のコードは、Javaにおける対策例です。
String expression = "//user[name/text() = $username and password/text() = $password]";
xpath.setXPathVariableResolver(v -> {
switch (v.getLocalPart()) {
case "username":
return username; // プレースホルダ$username位置には、リクエストパラメータusernameの値を割り当てる
case "password":
return password; // プレースホルダ$password位置には、リクエストパラメータpasswordの値を割り当てる
default:
throw new IllegalArgumentException();
}
});
+
演算子による文字列結合を用いてXPathを生成していた部分の実装が、$username
と$password
を使った実装(プレースホルダを使った実装)に置き換わっています。
こうすることで、「$username
と$password
の位置がすべて値である」と事前に決定しておくことができます。
結果として、'
などXPath上で意味をもつ記号が入力値に含まれていた場合でも、XPathの一部ではなく単なる文字列の一部として評価されます。
静的プレースホルダを用いた実装方法は、使用しているプログラミング言語、フレームワーク、ライブラリによって異なるため、アプリケーション構成に沿った対策が必要です。
まとめ
このように、XPathインジェクションの脆弱性があることで、攻撃者によってXPath式の意味が改変され、アプリケーションの意図しない操作をされてしまいます。
こういった被害を防ぐには、サイト設計の見直しや脆弱性診断などを行い、安全な状態になっていることを確認することをお勧めします。