XML正規化形式の紹介

XMLを回帰テストや電子署名などに適したものにする

XMLでは、ファイルやその他のデータ・ソースの(ビット単位での)詳細を、XML文書の抽象モデルから注意深く分離しています。これは2つのXML文書が等しいかどうか調べる時、例えばあるXML文書が何らかの方法で改変されたかどうか判断するために(例えばテスト・スイートの一部として)直接比較したり、セキュリティの目的から電子署名を比較したりする時には不便かも知れません。W3CではXML Canonicalization仕様(c14n)によって、この問題に対処しています。この仕様では、適切なビット単位での比較、そして一貫した電子署名を保証する、XML文書の標準形式を定義しています。この記事では、Uche OgbujiがXMLの正規化について紹介します。

Uche Ogbuji, Principal Consultant, Fourthought, Inc.

Photo of Uche OgbujiUche Ogbuji は、次世代の Web 技術を専門とするサービスの会社である、Uli, LLC の代表者です。Ogbuji 氏は XML、RDF、およびナレッジ管理アプリケーション用のオープン・ソース・プラットフォームである 4Suite の開発リーダーであり、Versa RDF 照会言語の開発リーダーでもあります。ナイジェリア出身のコンピューター・エンジニア兼ライターで、米国コロラド州ボールダー在住です。彼に関して詳しくは、彼のブログである Copia を見てください。



2004年 12月 07日

XMLの財産は文書として世の中に存在し、これはその構文規則に反映されています。XMLの構文は、データベースのレコードを対象としたデータ型式よりも厳密ではありません。XMLパーサは、エンコード形式のXML文書(エンコードはXML宣言の中で指定されます)をXML文書に関する情報を表現する抽象的なモデルに変換します。W3Cは、この抽象モデルをXML Infosetとして公開しましたが(参考文献参照)、XML処理の多くはエンコードされた(字句表現に大きな幅が許される)ソース形式の方に注目する必要があります。字句表現で許容されるものは、・・・属性の順序が任意となっている、要素名とその属性間などにおける空白の規則が柔軟である、文字の表現方法や特殊文字を別扱いするために幾つかの手段がある・・・等々です。名前空間によって、字句表現はさらに柔軟になります(例えば接頭辞の選択など)。その結果、XML 1.0の規則には完全に合致していながら、エンコードしたソースをバイト単位で比較すると非常に異なる文書が無数にあるのです。

字句表現が柔軟なために、回帰テストや電子署名などの分野では問題が起きてきます。例えば、リスト1の文書を正しい出力と想定した状況を含む、テスト・スイートを作った場合を考えてみてください。

リスト1. XML文書の例
<doc><a a1="1" a2="2">&#x31;&#x32;&#x33;</a></doc>

適切なXMLのテストを行うとき、リスト2に示す文書が正しい出力として認識されることを望むでしょう。

リスト2. リスト1のXML文書と同等な文書
<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <a
     a2="2" a1="1"
  >123</a>
</doc>

タグ内の空白が異なり、属性の順序が異なり、文字の実体が等価なリテラル文字に置き換わっています・・・が、Infosetsはそれでも同等なのです。これを、バイト単位の比較で同等と判断するのは困難です。電子署名の場合であれば、メッセージ通信システムを通して文書を送信する時に、その過程で文書が破壊されたり改変されたりしていないことを確認する必要があります。そのためには、暗号のハッシュや完全な電子署名が必要になってきます。ところが、メッセージ通信システムを通してリスト1 を送信すると、通常の処理によってリスト2 のように見える場合があるでしょう。そうなると、実質的には文書が変更されていないのに、単純なハッシュや電子署名は一致しないことになります。

この問題に対するW3Cの解決手段が、XMLの電子署名仕様の一部として開発されました。W3CではCanonical XML参考文献参照)を定義しています。これは、XMLで許容されている様々な変化形を全て除去して厳格な規則を強制することによって、整合性がありバイト単位での比較を可能とした、XMLの標準化された字句形式です。正規化形式(canonical form)に変換するプロセスは、正規化canonicalization: 通常は省略して「c14n」)として知られています。この記事では、XMLの正規化形式を学びます。

正規化形式の規則

仕様に示されているc14nプロセスの概要は、次のリストのようになります(私が少し編集しています)。

  • 文書は、UTF-8でエンコードされる
  • 改行は、入力時、構文解析前に「#xA」に標準化される
  • あたかも妥当性検証プロセッサによって行われるかのように、属性値が標準化される
  • あたかも妥当性検証プロセッサによって行われるかのように、省略時の属性値が各要素に追加される
  • CDATAセクションは、それらのリテラル文字の内容で置き換えられる
  • 文字と、構文解析された実体参照は(特殊文字を除いて)リテラル文字で置き換えられる
  • 属性値と文字コンテンツにある特殊文字は、(整形式のXMLでは普通ですが)文字参照に置き換えられる
  • XML宣言とDTDは除去される(注: 私は常々XML宣言を使うように勧めているのですが、正規化形式のXMLでXML宣言を除去している理由の背景は妥当だと思います)
  • 空要素は、開始タグと終了タグの対に変換される
  • 文書要素の外および、開始タグと終了タグの間にある空白は、標準化される
  • 文字コンテンツにある空白は全て保持される(改行の標準化中に削除された文字を除く)
  • 属性値の区切り文字は、引用符(二重引用符)に設定される
  • 余分な名前空間宣言は、各要素から除去される
  • 各要素の名前空間宣言や属性は、辞書順で並べられる

この時点では、一部の規則が不明確だからといって心配する必要はありません。実際に適用する場合に、もっと一般的な規則として充分な説明と例をこれから挙げて行きます。この記事では、DTDの妥当性検証に関係するc14nの手順は取り上げません。私はXML Infosetに関して何度か触れたことがありますが、興味深いことにW3CではInfosetの観点からではなく、Infosetよりも単純(よりクリーンだと言う人もいます)なデータ・モデルであるXPathデータ・モデルの観点からc14nを定義することにしたのです。これは恐らく正規化形式を理解する上では影響のない些細な点ですが、Infosetベースの技術にも取組む必要がある場合には、念頭に置くべきでしょう。


タグの正規化

タグの正規化は、タグ内の空白に関する特別な規則を適用することによって、また名前空間宣言と通常の属性を特定の順序で並べることによって行われます。下記は、正規化された開始タグを作るために、私自身が使っている非公式な手順です。

  1. 開始山括弧(<)に要素のQName(接頭辞+コロン+ローカル名)を続ける。
  2. デフォルト名前空間宣言、次に(もしあれば)その他全ての名前空間宣言をそれらの名前空間宣言で定義する接頭辞のアルファベット順に並べる。冗長な名前空間宣言(既に先祖要素で定義されており、無効にされていないもの)は全て省略する。各名前空間宣言の前には単一の空白を使い、等号の前後には空白は使わず、名前空間URIの前後は二重引用符で囲む。
  3. 全ての属性はアルファベット順とし、属性の前には単一の空白を使い、等号の前後には空白は使わず、属性値の前後は二重引用符で囲む。
  4. 最後に、山括弧を閉じる(>)。

正規化形式の終了タグは、これよりもずっと単純です。開始山括弧(<)に続いてスラッシュ(/)と要素のQNameを配置し、終了山括弧(>)で閉じます。リスト3は、正規化形式ではないXMLの例です。

リスト3. 正規化形式ではないXMLの例
<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:x="http://example.com/x" xmlns="http://example.com/default">
  <a
     a2="2" a1="1"
  >123</a>
  <b y:a1='1' xmlns="http://example.com/default" a3='"3"'
     xmlns:y='http://example.com/y' y:a2='2'/>
</doc>

リスト4は、同じ文書を正規化形式で表現したものです。

リスト4. リスト3の正規化XML表現
<doc xmlns="http://example.com/default" xmlns:x="http://example.com/x">
  <a a1="1" a2="2">123</a>
  <b xmlns:y="http://example.com/y" a3="&quot;3&quot;" y:a1="1" y:a2="2"></b>
</doc>

リスト3 を正規化するには、次のような変更が必要です。

  • XML宣言を除去する(文書は既にUTF-8になっているので、変換は必要ありません)
  • docに対するデフォルトの名前空間宣言を、他のどの名前空間宣言よりも前に配置する(この場合には、接頭辞xの前)
  • a開始タグ内にある空白を減らし、各属性の前に空白が一つだけとなるようにする
  • b開始タグにある冗長な名前空間宣言を削除する
  • 残りの名前空間宣言(接頭辞yの宣言)が、必ず他の全属性よりも前に現れるようにする
  • 残りの属性を、それぞれのQNameのアルファベット順に配置する(例えば「a3」の次に「y:a1」、その次に「y:a2」のようにする)
  • xmlns:y名前空間宣言と属性y:a1y:a2そしてa3に対する引用符による区切り文字を、単一引用符(')から二重引用符(")に変更する。a3の場合には、埋め込まれた二重引用符文字(")を&quot; として別扱いする

私は(PyXML に付属する)Python 用のc14nモジュールを使って正規化形式への変換をテストしてみました(PyXMLについては参考文献を見てください)。リスト5は、リスト3リスト4 に正規化するために私が使ったコードです。

リスト5. XMLを正規化するためのPythonコード
from xml.dom import minidom
from xml.dom.ext import c14n
doc = minidom.parse('listing3.xml')
canonical_xml = c14n.Canonicalize(doc)
print canonical_xml

文字データの正規化

正規化形式の文字データは、基本的に可能な限りリテラルにします。つまり文字の実体は生のUnicodeにし(そしてUTF-8としてシリアル化します)、CDATAセクションは実際の内容で置き換える・・・、などの変更が必要になります。これはコンテンツの文字データだけではなく、属性値の文字データについても同様です。属性は、そのDTDの形式によっても標準化されますが、主としてこれが影響するのは(この記事では扱わない)DTDを使用した文書です。リスト6は、c14n仕様にある例の一部を元にしたサンプル文書です。

リスト6. 文字データの正規化を説明するためのXMLの例
<?xml version="1.0" encoding="ISO-8859-1"?>
<doc>
   <text>First line&#x0d;&#10;Second line</text>
   <value>&#x32;</value>
   <compute><![CDATA[value>"0" && value<"10" ?"valid":"error"]]></compute>
   <compute expr='value>"0" &amp;&amp; value&lt;"10" ?"valid":"error"'>valid</compute>
</doc>

リスト7 は、同じ文書を正規化形式にしたものです。

リスト6 を正規化するには、次のような変更が必要です。

  • XML宣言を削除し、UTF-8に変換する
  • 文字参照の2 を、実際の数字としての 2 に変更する
  • CDATAセクションをその内容で置き換え、終了山括弧(>)を&gt; にし、&記号は&amp; に、そして開始山括弧(<)は&lt; にする
  • expr属性で使われている単一引用符を二重引用符で置き換え、次に二重引用符文字(")を &quot; にする

リスト6リスト7 では触れなかった重要な手順としてUTF-8への変換がありますが、これを記事の中でリストとして示すのは簡単ではありません。例えば元の文書の内容に、文字参照&#169; (著作権記号を表します)がある場合を考えてみてください。正規化形式ではこれを、16進数の C2 の後に16進数の A9 が続く構成のUTF-8の並びで置き換えるのです。


排他的な選択肢を忘れずに

場合によるとXML文書全体ではなく、そのサブツリーに署名したり、サブツリーを比較したりしたいことがあります。例えば、SOAPメッセージのボディにのみ署名してエンベロープを無視したいことがあるかも知れません。W3Cではこのために、対象とするサブツリー内外にある名前空間宣言を整理することのみに特化した、排他的正規化形式(exclusive canonical form)仕様を用意しています。

私は先ほど、接頭辞の選択によって多少の変化があり得ることに触れました。XML名前空間では、接頭辞は重要ではないと規定しています。ですから2つのファイルで名前空間接頭辞の選択が異なるだけであれば、その2つを同じものとして取り扱うべきなのです。残念ながら、c14nはこの点を網羅していません。完全に正当なXML処理操作で、接頭辞が変更されることがあり得るので、この問題が起こる可能性があることを念頭に置く必要があります。

正規化XMLは、常に手元に置くべき重要なツールです。皆さんが今すぐにXML関連のセキュリティやソフトウェアのテストに関係することはないかも知れませんが、一度c14nに慣れてしまうと、c14nが必要となる場面に出くわすことがいかに多いか驚くことでしょう。これらのツールは、最初に避けるべきとは気づかなかった危険箇所を回避するために有効なツールとして、大いに役立つのです。

参考文献

  • W3C XML Signature working group が作成した正規化XML仕様に目を通してください。Canonical XML Version 1.0 はW3C勧告(2001年3月)であり、Exclusive XML Canonicalization Version 1.0 も同様です(2002年7月)。どちらも正規化規則を定義するために非常に形式的な用語を使っているので、少し読み難いかもしれません。
  • Pythonライブラリで迅速にc14nを行ってください。インターネット・プロトコル標準の専門家であり、XML Signature WGのメンバーでもあるRich SalzとJoseph Reagleが、Pythonモジュールc14n.pyを開発しています。c14n.pyはPyXML に付属しています。
  • XML文書の情報の内容を抽象化した低レベルのモデルであるXML Information Set (Infoset) (W3C勧告、2004年2月)をよく見てください。
  • c14nなどのためにIBM WebSphere Studio を使ってください。IBM WebSphere Studioには、Javaやその他の言語でXML開発を自動化するツール一式が提供されています。IBM WebSphere Studioは、WebSphere Application Server と密接に統合されていますが、他のJ2EEサーバと共に使うこともできます。また、Jeffrey Liuによる「Building secure Web services with WebSphere Studio: Part 1: XML signature」(developerWorks, 2004年3月)も見てください。
  • developerWorksのDeveloper Bookstore には、XMLに関連した書籍が豊富に取り揃えられていますので、ぜひご覧ください。
  • developerWorksのXMLゾーン には、Uche OgbujiのXML的思索コラム を含めてXML関連の資料が豊富に用意されています(「 記事一覧」にも幾つか日本語訳された記事があります)。
  • XMLおよび関連技術においてIBM認証開発者になる方法についてはこちら を参照してください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML
ArticleID=240092
ArticleTitle=XML正規化形式の紹介
publish-date=12072004