MySQL 8.0 リファレンスマニュアル MySQL NDB Cluster 8.0 を含む

このページは機械翻訳したものです。

12.12 XML 関数

表 12.16 「XML 関数」

名前 説明
ExtractValue() XPath 表記法を使用した XML 文字列からの値の抽出
UpdateXML() 置換後 XML フラグメントを返します

このセクションでは、MySQL での XML および関連する機能について説明します。

注記

--xml オプションを付けて呼び出すと、mysql および mysqldump クライアントで XML 書式の出力を MySQL から取得できます。 セクション4.5.1「mysql — MySQL コマンドラインクライアント」およびセクション4.5.4「mysqldump — データベースバックアッププログラム」を参照してください。

基本的な XPath 1.0 (XML Path Language、バージョン 1.0) の機能を提供する 2 つの関数が使用可能です。 XPath の構文および使用方法に関する基本情報の一部は、このセクションの後半で説明しますが、これらのトピックの詳細はこのマニュアルの範囲外であるため、「XML Path Language (XPath) 1.0 標準」で明確な情報を参照する必要があります。 XPath がはじめてのユーザーや基本の復習を希望するユーザーに役立つリソースは、複数の言語で入手できる「Zvon.org XPath Tutorial」です。

注記

これらの関数はまだ開発中です。 XML および XPath 機能のこれらの側面やその他の側面については、MySQL 8.0 以降で引き続き改善します。 これらについて議論したり、質問したり、MySQL XML ユーザーフォーラムでほかのユーザーからの支援を得たりすることもできます。

これらの関数で使用される XPath の式では、ユーザー変数およびローカルストアドプログラム変数がサポートされています。 ユーザー変数は簡単にチェックされます。ストアドプログラムへのローカル変数は厳密にチェックされます (Bug#26518 も参照してください)。

ユーザー変数やストアドプログラムへのローカル変数を含む式は、その他の点 (表記法は除く) では、XPath 1.0 仕様で規定されている変数を含む XPath 式のルールに準拠する必要があります。

注記

XPath 式の格納に使用されるユーザー変数は、空の文字列として扱われます。 このため、ユーザー変数として XPath 式を格納することはできません。 (Bug #32911)

注記

XPath の構文および使用方法の詳細は、このマニュアルの範囲外です。 最終的な情報については、「XML Path Language (XPath) 1.0 仕様」を参照してください。 XPath がはじめてのユーザーや基本の復習を希望するユーザーに役立つリソースは、複数の言語で入手できる「Zvon.org XPath Tutorial」です。

一部の基本的な XPath 式の説明および例は、次のとおりです。

XPath の制限.  現在、これらの関数でサポートされている XPath 構文は、次の制限の対象となっています。

ExtractValue() および UpdateXML() への引数として渡される XPath 式の要素セレクタ内には、コロン文字 (:) が含まれている可能性があります。これにより、XML 名前空間の表記法を使用しているマークアップとの使用が有効になります。 例:

mysql> SET @xml = '<a>111<b:c>222<d>333</d><e:f>444</e:f></b:c></a>';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT ExtractValue(@xml, '//e:f');
+-----------------------------+
| ExtractValue(@xml, '//e:f') |
+-----------------------------+
| 444                         |
+-----------------------------+
1 row in set (0.00 sec)

mysql> SELECT UpdateXML(@xml, '//b:c', '<g:h>555</g:h>');
+--------------------------------------------+
| UpdateXML(@xml, '//b:c', '<g:h>555</g:h>') |
+--------------------------------------------+
| <a>111<g:h>555</g:h></a>                   |
+--------------------------------------------+
1 row in set (0.00 sec)

これは、いくつかの点で Apache Xalan およびその他の一部のパーサーで許可されているものと似ていますが、名前空間の制限や namespace-uri() および local-name() 関数の使用を必要とするよりも大幅に単純です。

エラー処理.  ExtractValue()UpdateXML() のどちらの場合でも、使用される XPath ロケータが有効であり、検索対象の XML が適切にネストされ、閉じられた要素で構成されている必要があります。 ロケータが無効な場合は、次のようなエラーが生成されます。

mysql> SELECT ExtractValue('<a>c</a><b/>', '/&a');
ERROR 1105 (HY000): XPATH syntax error: '&a'

xml_frag が適切にネストされ、閉じられている要素で構成されていない場合は、次の例に示すように、NULL が返され、警告が生成されます。

mysql> SELECT ExtractValue('<a>c</a><b', '//a');
+-----------------------------------+
| ExtractValue('<a>c</a><b', '//a') |
+-----------------------------------+
| NULL                              |
+-----------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1525
Message: Incorrect XML value: 'parse error at line 1 pos 11:
         END-OF-INPUT unexpected ('>' wanted)'
1 row in set (0.00 sec)

mysql> SELECT ExtractValue('<a>c</a><b/>', '//a');
+-------------------------------------+
| ExtractValue('<a>c</a><b/>', '//a') |
+-------------------------------------+
| c                                   |
+-------------------------------------+
1 row in set (0.00 sec)
重要

UpdateXML() への第 3 引数として使用される置換用の XML は、適切にネストされ、閉じられている要素のみで構成されているかどうかを判断するためにチェックされません

XPath インジェクション.  コードインジェクションは、権限やデータへの不正アクセス権を取得するために、悪意のあるコードがシステムに導入された場合に発生します。 これは、ユーザーが入力したデータの型や内容について開発者が行なった想定の悪用に基づいています。 これに関しては、XPath も例外ではありません。

この問題が発生する可能性のある一般的なシナリオは、次のような XPath 式を使用して、ログイン名とパスワードの組み合わせを XML ファイル内で見つかったものと一致させることで承認を処理するアプリケーションのケースです。

//user[login/text()='neapolitan' and password/text()='1c3cr34m']/attribute::id

この XPath 式は、次のような SQL ステートメントと同等です。

SELECT id FROM users WHERE login='neapolitan' AND password='1c3cr34m';

XPath を使用している PHP アプリケーションでは、次のようにログインプロセスが処理される可能性があります。

<?php

  $file     =   "users.xml";

  $login    =   $POST["login"];
  $password =   $POST["password"];

  $xpath = "//user[login/text()=$login and password/text()=$password]/attribute::id";

  if( file_exists($file) )
  {
    $xml = simplexml_load_file($file);

    if($result = $xml->xpath($xpath))
      echo "You are now logged in as user $result[0].";
    else
      echo "Invalid login name or password.";
  }
  else
    exit("Failed to open $file.");

?>

入力時にはチェックが実行されません。 これは、悪意のあるユーザーがログイン名とパスワードの両方に ' or 1=1 と入力することで、テストを回避できることを意味します。その結果、$xpath が次のように評価されます。

//user[login/text()='' or 1=1 and password/text()='' or 1=1]/attribute::id

角括弧内の式は常に true と評価されるため、事実上、XML ドキュメント内のすべての user 要素の id 属性に一致する次の式と同じです。

//user/attribute::id

この攻撃を回避する方法の 1 つは、$xpath の定義内に挿入される変数名を単に引用符で囲むだけです。これにより、Web フォームから渡された値が強制的に文字列に変換されます。

$xpath = "//user[login/text()='$login' and password/text()='$password']/attribute::id";

これは、SQL インジェクション攻撃を回避する際に推奨されることの多い方法と同じです。 一般に、XPath インジェクション攻撃を回避するために従うべき方法は、SQL インジェクションを回避するための方法と同じです。

SQL インジェクション攻撃を使用すればデータベーススキーマに関する情報を取得できるように、XPath インジェクションを使用すれば、Amit Klein 氏の論文『Blind XPath Injection』(PDF ファイル、46K バイト) で説明されているように、XML ファイルをスキャンして構造を明らかにできます。

クライアントに返送される出力をチェックすることも重要です。 MySQL の ExtractValue() 関数を使用すると何が発生する可能性があるのかを検討します。

mysql> SELECT ExtractValue(
    ->     LOAD_FILE('users.xml'),
    ->     '//user[login/text()="" or 1=1 and password/text()="" or 1=1]/attribute::id'
    -> ) AS id;
+-------------------------------+
| id                            |
+-------------------------------+
| 00327 13579 02403 42354 28570 |
+-------------------------------+
1 row in set (0.01 sec)

ExtractValue() は複数の一致を空白で区切られた単一の文字列として返すため、このインジェクション攻撃によって、users.xml 内に含まれるすべての有効な ID が単一の出力行としてユーザーに提供されます。 追加の保護手段として、ユーザーに返される前に出力のテストも行うべきです。 次に、単純な例を示します。

mysql> SELECT @id = ExtractValue(
    ->     LOAD_FILE('users.xml'),
    ->     '//user[login/text()="" or 1=1 and password/text()="" or 1=1]/attribute::id'
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT IF(
    ->     INSTR(@id, ' ') = 0,
    ->     @id,
    ->     'Unable to retrieve user ID')
    -> AS singleID;
+----------------------------+
| singleID                   |
+----------------------------+
| Unable to retrieve user ID |
+----------------------------+
1 row in set (0.00 sec)

一般に、ユーザーにデータをセキュアに返すためのガイドラインは、ユーザー入力を受け入れるためのガイドラインと同じです。 それらは、次のように要約できます。