エスケープを無くせばOK、と勘違いして失敗した事例 XPath 1.0

12月 6, 2013 Security
(Last Updated On: 2018年8月24日)

昨日のブログでは.NETにはSQLのエスケープAPIが無いので、セキュリティ対策として本末転倒な状態になっている事を紹介しました。もう一つXPath 1.0の失敗例を紹介します。

XPath 1.0の定義にはエスケープが定義されていません。参考:XPathクエリ(1)

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

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

文字リテラルの定義はコレだけです。つまり文字列は ‘ (シングルクオート) または ”(ダブルクォート) で囲み、それぞれ ‘ と ” が現れてはならない、としか定義されておらずエスケープ処理が定義されていません。

恐らくXPath 1.0を定義した方たちは「エスケープは悪!エスケープは無い方が良い」と考え作らなかったのだと思います。

しかし、XPathはXML文書を検索するクエリ言語です。XML文書の検索には普通のテキスト検索が必要です。文字列にシングルクォートとダブルクォートの両方がある場合はどうすれば良いのでしょうか?以下のコードが解決策です。参考:XPathクエリ(2)

function xpath_escape_string($input) {
    if (false === strpos($input, "'")) {
        return "'$input'";
    }
    if (false === strpos($input, '"')) {
        return "\"$input\"";
    }
    return "concat('" . strtr($input, array("'" => '\', "\'", \'')) . "')";
}

このコードはエスケープAPIが無いのでXPath 1.0の文字列連結concat関数を使ってシングルクォートとダブルクォート両方を含む文字列を処理できるようにしています。この関数は

Let's "PHP Security"

という文字列なら安全な

concat('Let', "'", 's "PHP Security"')

という文字列に変換します。

さすがに失敗した、と気づいてXPath 2.0からエスケープ処理が定義されました。XPath 2.0なら、シングルクォートで囲った文字リテラルならシングルクォートでエスケープするので

Let''s "PHP Security"

とするだけです。

concat('Let', "'", 's "PHP Security"')

Let''s "PHP Security"

どちらが解りやすいでしょうか?

XPathでは属性を使った検索もできますが、インタラクティブにXMLドキュメントを検索するアプリケーションに属性を使うことは考えられません。属性はインタラクティブなクエリに向かないだけでなく、属性を使うとクエリの書き方が変わります。XPathクエリについて詳しく知りたい方はXPathクエリ(1)XPathクエリ(2)を参照してください。

XPath 1.0はテキストインターフェースなのにエスケープ処理を定義しなかった為におかしくなってしまいました。XPathを作った人達は失敗をXPath 2.0で修正しました。

テキストインターフェースを持つシステムの場合、エスケープ処理は基本中の基本の処理です。エスケープ処理が無いことはおかしいのです。そしてテキストインターフェースを持つシステムでプログラムをつくるプログラマにエスケープ処理を教えない事もおかしいのです。

Webアプリセキュリティの基本ルール根本的なセキュリティ対策とは?もご覧ください!

類似問題:

DBMSの脆弱なAPI仕様は何時まで放置されるのか?

 

投稿者: yohgaki