XPathクエリ(1)

(更新日: 2014/12/08)

XPathはXML文書をクエリして要素を取り出す仕組みです。XML文書を検索して結果を返します。

SimpleXMLにはxpathメソッドが用意されています。
SimpleXMLElement::xpath


DOMにはDOMXPathクラスが用意されています。
The DOMXPath class

いずれもXPathクエリの仕組みは用意されていますが、現在(PHP5.5)の所はエスケープ関数が用意されていません。しかし、XPathクエリを安全に実行するにはエスケープは欠かせません。

XPathには1.0と2.0の仕様があり、それぞれエスケープ仕様を定めています。

XPath 1.0の仕様
XPath 2.0の仕様

XPath 1.0のリテラル定義(3.7 Lexical Structure)

Literal ::= ‘”‘ [^”]* ‘”‘ | “‘” [^’]* “‘”

リテラルは” (ダブルクォート)または’ (シングルクォート)で囲みます。それぞれ ” または ‘ がリテラルの中に現れてはならない事とになっています。XPath 1.0の仕様書にはエスケープ仕様が記載されていません。

XPath 2.0のリテラル定義(3.1.1 Literals)

[42] Literal ::= NumericLiteral | StringLiteral
[43] NumericLiteral ::= IntegerLiteral | DecimalLiteral | DoubleLiteral
[71] IntegerLiteral ::= Digits
[72] DecimalLiteral ::= (“.” Digits) | (Digits “.” [0-9]*)
[73] DoubleLiteral ::= ((“.” Digits) | (Digits (“.” [0-9]*)?)) [eE] [+-]? Digits
[74] StringLiteral ::= (‘”‘ (EscapeQuot | [^”])* ‘”‘) | (“‘” (EscapeApos | [^’])* “‘”)
[75] EscapeQuot ::= ‘””‘
[76] EscapeApos ::= “””
[81] Digits ::= [0-9]+

XPath2.0ではエスケープ方法が明確に定義されており、 データベースと同様にリテラルのクオート文字でクオート文字をエスケープするようになっています。つまり、

とします。

XPath 1.0にはエスケープ仕様が定義されていません。どのXPathを利用しているか知った上でエスケープまたはパラメータのチェックを行わなければなりません。

PHPのSimpleXMLとDOMモジュールはlibxml2と呼ばれるライブラリを利用しています。現在の所、libxml2はXPath 1.0をサポートしており2.0はサポートしていません。XML文書のノード名・属性名に ” または ’ を利用しようとするとエラーとなりパースできません。またXPathクエリのクエリ文字列のノード名・属性名に ‘ または ” が含まれている場合、エラーが発生し処理されません。

クエリ文字列にクオート文字がある場合のエラー例

つまりノード名などには ‘ や ” は利用できません。これはXML仕様書(XML 1.0)で確認できます。ノード名や属性名に利用できる文字は 2.3 Common Syntactic Constructs で定義されており ‘ や ” は含まれない事が分かります。

2.3 Common Syntactic Constructs

[4] NameStartChar ::= “:” | [A-Z] | “_” | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
[4a] NameChar ::= NameStartChar | “-” | “.” | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
[5] Name ::= NameStartChar (NameChar)*

ただし、ノードの値や属性値には ‘ と ” は利用可能です。この為、クエリには ‘ と ” を利用可能です。

クオート文字を含んだ検索例

出力

サンプルスクリプト中の

の中で

とダブルクォートで囲んだ文字列の中にシングルクォートが在るため問題なく検索できています。しかし、これが

などがあった場合には不正なクエリの送信可能になります。

XPathクエリについては、続きを書くことにします。

PHPのセキュリティ入門書に記載するコンテンツのレビューも兼ねてブログを書いています。コメント、感想は大歓迎です。

参考リンク:

Comments

comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です