次の方法で共有


WS-Security 入門

Scott Seely
Microsoft Corporation

October 2002

対象:
   Web サービス仕様(WS-Security、WS-Security 補遺)

概要: この記事では、SOAP メッセージ自体にセキュリティ機能を組み込むために、WS-Security を利用する方法を解説します。特に、WS-Security で考慮されているセキュリティ要件である認証、電子署名、暗号化について検討します。

目次

はじめに
日常生活との対比
既存の概念を SOAP メッセージに適用する
WS-Security SOAP Header
まとめ
他の情報源

はじめに

WS-Security についての解説を始める前に、WS-Security が作成された理由を理解する必要があると思います。Web サービスの学習を始めたばかりの多くの人にとって、SOAP の目的は HTTP を利用して 2 つのエンドポイントの間でメッセージを送受信するためのものという理解でしょう。HTTP を利用すれば、送信元を認証したり、メッセージに電子署名を施したり、メッセージの内容を暗号化することもできます。これによって、送信元の認識、メッセージに改ざんがないことの確認、ネットワークをのぞき見られても送受信されたデータの内容がわからないようにすることといった、メッセージをセキュアに保つための要件を満たすことができます。しかし、SOAP メッセージングというものをもっと大きな側面から見ている人々にとっては、HTTP ベースのセキュリティでは役不足なのです。単純なリクエストとレスポンスの組み合わせではない、より複雑な経路を通したり、 HTTP ではない転送プロトコルを利用したりしてメッセージを送受信する場合が考えられます。メッセージのアイデンティティ(身元)、完全性、秘匿性が複数のポイントで構成される送信経路の中で保たれていなければなりません。ある経路の中では、複数の暗号化キーが使われるかもしれません。信頼されたドメインを超えて通信が行われるかもしれません。HTTPのセキュリティメカニズムでは、ポイントツーポイントのセキュリティ要件にしか対応できません。ここで示したような複雑な問題に対処するためには、エンドツーエンドのセキュリティの仕組みが必要です。WS-Security は、複数のポイントをまたがってメッセージの通信経路が作られている場合に、メッセージのセキュアな状態を維持するための方法を示しています。

    この記事は、XML の正規化(Canonicalization)XML 電子署名XML 暗号の知識 を前提として書かれています。

WS-Security は既存の標準と仕様を活用してセキュリティに対処します。このため、WS-Security の中だけで完全なセキュリティ・ソリューションを定義する必要はなくなっています。IT業界は、既にこれらの問題を解決するソリューションをたくさん提供しています。Kerberos と X.509 による認証技術が既にあります。X.509 は既存の PKI の技術をキーの管理に利用しています。XML メッセージの内容を暗号化する方法と、電子署名を付加する方法は、XML 暗号と XML 電子署名の仕様に記述されています。XML に署名を施すことができるようにする方法は、XML 正規化(Canonicalization)仕様で説明されています。既存の仕様に追加して、WS-Security は、これらのメカニズムを SOAP メッセージに、トランスポートに依存しない形で組み込むためのフレームワークを提供します。

WS-Security は、セキュリティ関連のデータを運ぶための SOAP の Header 要素の内容を定義しています。XML 電子署名が使われる場合は、ヘッダーにはメッセージが署名されている方法、使われたキー、署名済みのデータを示す情報が含まれます。これらはXML電子署名仕様で定義されているものです。同様に、メッセージの要素が暗号化されている場合は、XML 暗号仕様で規定されている暗号化の情報が WS-Security のヘッダーに含まれることになります。WS-Security は署名や暗号化の形式は指定しません。WS-Security には、他の仕様で規定されたセキュリティの情報を SOAP メッセージに組み込む方法が規定されています。WS-Security の主目的は、XMLベースのセキュリティ・メタデータのコンテナを規定することです。

既存のプロトコルを使ったメッセージの認証、完全性、秘匿性の他に、WS-Security には UsernameToken 要素を使って単純なユーザーのクレデンシャルを転送するメカニズムが定義されています。メッセージの暗号化や電子署名を行うときに使われたバイナリ・トークンを送信できるようにするために、 BinarySecurityToken 要素も定義されています。このヘッダーの中に、メッセージの送信元、メッセージの署名方法、メッセージの暗号化方法などを含めることができます。WS-Security は、セキュリティ情報を SOAP メッセージの一部として含めることで、Web サービスの世界にエンドツーエンドのセキュリティ・ソリューションを提供します。

この記事では、WS-Security と関連する仕様を利用して、SOAP メッセージ自体にセキュリティ機能を組み込む方法を解説します。具体的には、WS-Security が対象とする次の内容を解説します。

  • 認証
  • 電子署名
  • 暗号

この 3 つは主要なセキュリティ要件であり、次のような質問に答えるためのものです。

  • 「誰に対してアクセスを許可しようとしているのか。」
  • 「到達する前にメッセージが改ざんされていないか。」
  • 「メッセージは予定通りの相手から送信されたものか。」
  • 「特定の相手にしか公開したくない情報を隠す方法は。」

はじめに、日常生活との類似点を考察してみましょう。

日常生活との対比

WS-Security の目的を理解するために、まず現実世界との対比をしてみましょう。日常生活の中で、いつどのようにクレデンシャルを利用しているかに注目してみます。結局のところ、毎日の生活で私たちはいつもクレデンシャルを利用しているのです。誰かに年齢を尋ねられたら、財布の中から運転免許証を取り出すでしょう。何かを購入して、代金を現金で支払わないことにした場合は、クレジットカードを取り出して、カード会社に対する自分の証明にするはずです。国境を越えようとするときや外国にいる間は、パスポートが自分自身を証明してくれます。これらすべてがクレデンシャルです。クレジットカードや運転免許証やパスポートは、それを持っている人物がそこに書かれている人物であるということを表明するための書類です。ですが、これらのものは持ち主を認証するわけではありません。書類では認証は実行できません。紙の書類の場合、人間が認証を実行します。それでは、認証する側はどのような作業をするのでしょうか。

運転免許証やパスポートを提示した場合、受け取った側では書類が本物で、持ち主が正当であることを検証するためにいくつかの作業を行います。

  • どちらの書類も書類の正当な持ち主の写真と、身長、体重、眼球の色などの特徴が記されています(訳注:米国の場合)。書類を受け取った側では、提示した人物がその書類に記述されているとおりの人物かどうかを確認します。
  • 書類には決められた有効期限があります。これによって書類に記述されているのが最近のデータであることを保証しています。
  • 書類には署名が含まれているため、持ち主の署名と比較することができます。他人の署名を正確に複製するのは難しいので、その人物の特徴の記述と組み合わせることで身元の確認に役立てることができます。

書類には、他にも重要な情報が書かれています。まず、書類が正当であることを簡単に確認できるように、何らかの印がついています。また書類自体が、たとえば地方自治体や国など、正しい身元情報を提供すると多くの人に信じられている組織から、発行されています。クレジットカードにも触れましたが、これは運転免許証やパスポートとは次の点で異なります。

  • 政府・自治体ではなく、銀行から発行されています。
  • 身元の証明情報として、カードの所有者の名前と署名しか書かれていません。
  • 政府から発行された証明書などの別の書類と一緒に提示されて始めて、身元の証明に利用することができます。

それでは、クレジットカードのようなものの存在意義は何でしょうか。

クレジットカードを使う場合、認証は一般に署名だけに頼っています。認証をより確実にするために、写真が貼ってあるカードもあります。クレジットカードによる認証はそれほど確実ではないため、カードともに政府機関発行の証明書の提示が求められることもしばしばあります。セキュリティ用語を使って説明すると、クレジットカードを提示した人物は、物やサービスの対価をそのカード(が表す口座)に対して請求してもよい、また販売店に対する支払いはカード会社が行う、という 2 点を表明していることになります。販売店では、目の前の人物と政府機関が発行した証明書に付いている写真とを比較して、その人物がカードの正当な持ち主であることを検証することができます(もちろん、電話やインターネットを通じてカードによる支払いを行った場合、この部分は実行できません。ですが、このような場合でも、カードの誤用から正当な持ち主を保護するための何らかのメカニズムが存在するといっていいでしょう)。

既存の概念を SOAP メッセージに適用する

WS-Security は、上記のような身元の確認とアクセス制御の概念を SOAP メッセージングの世界にも持ち込もうとしています。SOAP メッセージを使って何か意味あることを行うためには、メッセージに次のような情報が含まれていなければなりません。

  • メッセージに含まれるエンティティの識別
  • エンティティがメンバーとして所属するグループの証明
  • エンティティが保持しているアクセス権限の証明
  • メッセージが改ざんされていないことの証明

また、許可されていないときは情報を開示しないようにするためのメカニズムも求められています。個人の身元を確認するときは、運転免許証やパスポートを使います。メンバーカードを見せれば、何らかの権限を持っていることを証明できます。筆者の財布の中には、物やサービスを買うためのカードや、図書館で本を借りるためのカード、医療に関する請求を保険会社にまわすためのカード、スーパーで割引を受けるためのカードなどが入っています。WS-Security はこれと同じ概念を、SOAP メッセージを使って行うことができるようにします。メッセージの送信者の身元の識別と、その権限の表明にセキュリティトークンを使うことで、メッセージには次のような情報を含むことができるようになります。

  • 送信者の識別:私は Joe User です。
  • 所属しているグループ:私は ColdRooster.com の開発者です。
  • 権限の表明:ColdRooster.com の開発者として、私はデータベースを構築し、Webアプリケーションを ColdRooster.com のマシンに組み込むことができます。

ColdRooster.com のサーバーに新しいデータベースを構築するメッセージを、Kerberos などの認証技術を用いて作成するためには、アプリケーションでは多数のセキュリティトークンを取得しなければなりません。まず、メッセージを作成しているアプリケーションは、Joe User のセキュリティトークンを取得して、Joe User として振舞うことができるようにする必要があります。このトークンは、Joe User がユーザー名とパスワードの組、またはスマートカードを使ってログインしたときに提供されます。セキュリティ機構として Kerberos を使っているとすると、その環境には Joe がログインしたときにチケット認可チケット (TGT) を提供するキー配布センターがあります。ColdRooster.com に新しいデータベースを構築するに当たって、Joe はチケット認可サービスにアクセスして Joe が新しいデータベースを構築する権限を持っていることを示すサービスチケットを発行してもらいます。このサービスチケットは、ColdRooster.com のデータベースサーバーに提示されます。データベースサーバーはチケットを検証して、Joe が新しいプロセスを作成することを許可します。

WS-Security では、上記のような一連のセキュリティ関連のやりとりにかかわる情報は SOAP ヘッダーに組み込まれます。WS-Security はクレデンシャルを2通りの方法で処理できます。まず、Webサービスが独自の認証を行っている場合に、UsernameToken という特別な要素を利用して、ユーザー名とパスワードを渡す方法があります。UsernameToken 要素は WS-Security で定義されています。また、Kerberos のチケットや X.509 証明書のようなバイナリ認証トークンを利用するために、BinarySecurityToken 要素が定義されています。

今後一般的に行われるであろうメッセージの流れを図 1 に示します。

図 1 一般的なメッセージの流れ

セキュリティ・トークン・サービスとは、Kerberos や PKI、あるいはユーザー名とパスワードの組を使った認証サービスです。このサービスは Web サービスではないかもしれません。たとえば、Kerberos のチケット認可サービスに対しては、Kerberos プロトコルを使う必要があります。Kerberos プロトコルを利用するために、オペレーティングシステムのセキュリティ機能を使う必要があるかも知れません。クライアントは、何らかの手順でセキュリティ・トークン・サービスからトークンを取得して、そのトークンをメッセージに埋め込みます。クライアントは自分しか知らないデータを使ってメッセージに署名したほうがよいでしょう。サーバーは様々な方法で署名を検証することになります。認証に UsernameToken を使っている場合は、クライアントはパスワードをハッシュして、パスワードでメッセージに署名します。サーバーでは、サーバー側で生成した署名データと実際にメッセージに含まれている署名データを比較して、メッセージの送信者が本当にそのクライアントであることを検証できます。

X.509 証明書を使う場合は、メッセージには秘密キーで署名することができます。メッセージには、BinarySecurityToken として証明書が含まれている必要があるでしょう。X.509 を使うと、X.509 の公開キーを知っていれば、誰でも署名を検証できます。また、Kerberos を使う場合は、メッセージは Kerberos のチケットに埋め込まれているセッションキーを使って署名を施したり、暗号化したりすることができます。Kerberos のチケットは、受信者のキーで暗号化されているため、指定された受信者だけがチケットの暗号を解除してセッションキーを取り出し、署名の検証を行うことができます。

認証が重要になる場合は、SOAP メッセージに署名を施したり、暗号化したりできることが欠かせません。なぜなら、メッセージに正当な身元を表すトークンが含まれているだけでは不十分だからです。このトークンが正当なメッセージから切り離されて、悪意の攻撃者のメッセージに組み込まれてしまう可能性があります。そのため、メッセージで使われている身元識別情報の正当な所有者がメッセージを作成したのだという証拠を提供する必要があるのです。XML 電子署名を使ってメッセージに署名をしていないと、そのメッセージが改ざんされていたり、身元識別トークンが悪用されていたりする可能性があるのです。

ここまでの解説で、WS-Security の目的が理解できたことと思います。そこで、少し内容を掘り下げて、それをどのように実現するのかを見ていきましょう。

WS-Security SOAP Header

このセクションからは、XML の断片を使って解説します。XML の名前空間を毎回書いていると例がわかりにくくなるため、次の名前空間の宣言はあらかじめ行われているものと考えてください。

Table 1: XML Namespaces

名前空間接頭辞 説明 名前空間 URI
Xs XML Schema http://www.w3.org/2001/XMLSchema
Wsse WS-Security https://schemas.xmlsoap.org/ws/2002/07/secext
Wsu Utility 要素 https://schemas.xmlsoap.org/ws/2002/07/utility
Soap SOAP 要素 https://schemas.xmlsoap.org/soap/envelope/

WS-Security 仕様では、新しい SOAP ヘッダーが定義されています。WS-Security の SOAP ヘッダーに含まれているものを理解するためには、まずその要素のスキーマ (の断片) を見るのが近道だと思います。

<xs:element name="Security">
    <xs:complexType>
        <xs:sequence>
        <xs:any processContents="lax" 
            minOccurs="0" maxOccurs="unbounded">
        </xs:any>
        </xs:sequence>
        <xs:anyAttribute processContents="lax"/>
    </xs:complexType>
</xs:element>

ご覧のとおり、Security というヘッダー要素には、XML のどんな要素や属性でも含むことができるようになっています。これによって、アプリケーションで必要であればどんなセキュリティメカニズムでも、このヘッダーに組み込めるようになっています。わかりにくいようなら、SOAP のヘッダーとボディについて考えてみてください。ヘッダーとボディにはXML要素の集合を含むことができます。SOAP の仕様には、これらの要素の内容についてほとんど言及がありません。XML の処理命令は含めることができないと規定されているくらいです。

ヘッダーの性質からして、WS-Security にもこのような構造が必要でした。送信者の権限や身元を識別するための複数のセキュリティトークンを運ぶことができなければならないからです。メッセージが署名されていれば、ヘッダーには署名の方法やキーの保管に関する情報が含まれていなければなりません。キーはメッセージに含まれているかもしれないし、単に参照されているだけでどこか別の場所に保管されているかもしれません。また、暗号化に関する情報もヘッダーに乗せて運ぶことができなければなりません。

ところで、各中継局(Intermediary) では、どの WS-Security のヘッダーが自分宛のもので、どれは自分で解析する必要はないヘッダーなのかをどうやって知ればいいのでしょうか。SOAP メッセージには複数の WS-Security ヘッダーが含まれている可能性があります。それぞれのヘッダーは、特定のアクターによって識別されます。2 つ以上の WS-Security ヘッダーが同じアクターを指していたり、アクターの指定をしていなかったりすることは禁止されています。これによって、中継局ではどの WS-Security ヘッダーに必要な情報が含まれているのかを、簡単に調べることができます。もちろん、各中継局はどのアクター URI が 「自分」 を指しているのかを知っていなければなりません。URI とアクターを関連付けて、中継局がすべきことを指定するためには、プログラミングが必要です。SOAPヘッダーのアクター属性は、「このヘッダーはアクター URI で示されている役割を持っているエンドポイントに対して送信されている」 ということを示すためのものです。あるURIがどのアクターを指すかを決定するのは、Webサービスの設計チームです。これは、ある中継局が様々な役割を果たす可能性もあるということです。つまり、中継局はゼロ、1 つ、またはそれ以上のヘッダーを処理する可能性があります。場合によっては、ある中継局が複数のセキュリティヘッダーを処理することもありえます。

訳注: 中継局とは、SOAP メッセージが送信相手に届くまでに通過する一連の SOAP ノード(SOAP サーバー)です。ごく基本的な Web サービスでは、クライアントとサーバーの 2 つのプレイヤーしか登場しないこともありますが、Webサービスの規模が大きく複雑になると、1 つのメッセージに対して複数の SOAP サーバーが処理を担当することがありえます。たとえば本稿で解説しているセキュリティは、専用の SOAP サーバーで処理され、その後正しいデータだけが本当の送信相手に到達するような仕組みが考えられます。これは、ちょうど Web アプリケーションの世界におけるプロキシやファイアウォールと同じ考え方です。

WS-Security 補遺

WS-Security について評価している間に、特にセキュリティに関して明白にしておかなければならない項目がいくつか見つかりました。また、Web サービス一般についても、追加しておかなければならない項目がありました。(訳注: そのために、WS-Security仕様への追加条項として、WS-Security 補遺が定められました。)セキュリティに関して補遺に記述されている内容は、この記事全体でカバーしています。このセクションでは、セキュリティとは直接関係しない 2 つの項目、wsu:IDwsu:Timestamp について確認することにします。補遺には、この 2 つが何をするもので、どのように利用すべきかについて記述されています。

wsu:Id

Id は XML Schema の ID 型の属性です。この属性は、Web サービスの中継局や受信者の処理を単純化するために追加されました。この属性の値は、XML 文書内の他の場所の値と重複してはいけません。補遺には、この属性が GXA 仕様における一意の識別子として使われるという以外には、特に用途は詳細に解説されていません。他の仕様が Id 属性の利用方法にもっと制限を加えることもまったくの自由です。

wsu:Timestamp

メッセージ指向のシステムにおいては、データがタイムリーに送られていることが重要になります。データが古すぎる場合は、受信せずに放置することもあります。到着した2つのメッセージが矛盾していた場合、どちらのメッセージを実行してどちらを無視するのかを判断する材料としても、タイムスタンプが使われることがあります。WS-Security や他の GXA 仕様において時間に関連する問題を扱うために、wsu:Timestamp 要素といくつかのヘルパー要素が定義されました。

メッセージのライフサイクルにおいて重要な時間として、作成日時、有効期限、受信日時があります。作成日時と有効期限がわかれば、データが処理すべき最新のものか、古すぎるので捨ててもいいものかどうかが受信側で判断できます。このデータを保持する要素は次のように定義されています。

  • wsu:Created: メッセージの作成日時を含みます。
  • wsu:Expires: メッセージの有効期限を示します。送信者、あるいは中継局によって設定されます。
  • wsu:Received: 特定の中継局がメッセージを受信した日時を示します。

上記の要素はすべて個々に独立して存在することも、wsu:Timestamp 要素の子要素として存在することもできます。それぞれを一意に識別するために、 wsu:Id 属性を利用することも可能です。デフォルトでは、これらのタイムスタンプは xs:dateTime 型として表されます。他の標準的ではないがある問題領域にとって意味のあるタイムスタンプを許容するために、これらの要素には ValueType 属性を付けることができます。この属性は、日時が xs:dateTime で表せるときは不要です。

wsu:Received 要素には、 wsu:Createdwsu:Expires にはない属性が2つ定義されています。1 つはその要素に関連するアクターを示す URI を記述する Actor 属性です。もう 1 つはそのアクターが原因で発生した遅延時間をミリ秒で記述する Delay 属性です。

先述したとおり、 wsu:Receivedwsu:Createdwsu:Expires は他の構造に含めて利用することもできます。たとえば、特定の要素がメッセージに追加された時間を表すために wsu:Created 要素を使うことができます。これらの要素を複数同時に利用する場合は、それを wsu:Timestamp 要素の子要素にします。wsu:Timestamp要素の中には、上記の3つの要素は1つずつしか含めることができません。タイムスタンプがメッセージ全体に対して適用される場合は、wsu:Timestamp 要素は soap:Header ノードの直下に配置されます。たとえば、メッセージの有効期限を5分間に設定するためには、次のようなwsu:Timestampヘッダーを利用します。

<wsu:Timestamp>
    <wsu:Created wsu:Id=
        "Id-2af5d5bd-1f0c-4365-b7ff-010629a1256c">
            2002-08-19T16:15:31Z
    </wsu:Created>
    <wsu:Expires wsu:Id=
        "Id-4c337c65-8ae7-439f-b4f0-d18d7823e240">
            2002-08-19T16:20:31Z
    </wsu:Expires>
</wsu:Timestamp>

ここまでの解説で、WS-Security を利用して認証、署名、暗号化を行う方法についての解説を行う準備ができたことと思います。

認証

WS-Security は、無限のユーザー認証方式をサポートしています。仕様書では、そのうち特に 3 種類の方法について触れています。

  • ユーザー名/パスワード
  • X.509 証明書を使ったPKI
  • Kerberos

このセクションでは、これらの認証方式がそれぞれどのように機能し、利用する情報をどのように SOAP メッセージにエンコードするかについて解説します。

ユーザー名/パスワード

送信元のクレデンシャルを伝達する方法として、ユーザー名とパスワードの組を利用することができます。HTTP の基本認証やダイジェスト認証でもこの仕組みが使われています。実際、HTTP ダイジェスト認証の仕組みが分かっていれば、この認証メカニズムを理解するのは難しくありません。ユーザー名とパスワードの組み合わせで構成されたクレデンシャルを送信するために、WS-Security には UsernameToken 要素が定義されています。この要素のスキーマは次のようなものです。

<xs:element name="UsernameToken">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Username"/>
            <xs:element ref="Password" minOccurs="0"/>
        </xs:sequence>
        <xs:attribute name="Id" type="xs:ID"/>
        <xs:anyAttribute namespace="##other"/>
    </xs:complexType>
</xs:element>

このスキーマの断片では、2 つの型(UsernamePassword )を参照しています。この 2 つは基本的には文字列で、必要に応じて属性を含むことができるようになっています。Password 要素には、パスワードがどのような形で送信されているかを示す Type という名前の属性が定義されています。パスワードはプレーンテキストかまたはダイジェストの形式で送信できます。SOAP メッセージにUsernameTokenを入れて送信する場合、そのXMLは次のような形になります。

<wsse:UsernameToken>
    <wsse:Username>scott</wsse:Username>
    <wsse:Password Type="wsse:PasswordText">password</wsse:Password>
</wsse:UsernameToken>

この例では、パスワードはプレーンテキストで送信されています。これではセキュリティ・ソリューションとしては不足です。より安全な形でパスワードを送信するには、ダイジェストを送信します。

<wsse:UsernameToken>
    <wsse:Username>scott</wsse:Username>
    <wsse:Password Type="wsse:PasswordDigest">
        KE6QugOpkPyT3Eo0SEgT30W4Keg=</wsse:Password>
    <wsse:Nonce>5uW4ABku/m6/S5rnE+L7vg==</wsse:Nonce>
    <wsu:Created xmlns:wsu=
        "https://schemas.xmlsoap.org/ws/2002/07/utility">
            2002-08-19T00:44:02Z
    </wsu:Created>
</wsse:UsernameToken>

SHA1 ハッシュを使ってパスワードを解読しづらくしているため、セキュリティ機能が少し向上しました。パスワードのダイジェストは、ノンスと作成日時とパスワードを連結したものにハッシュをかけたものです。ノンスは 16 バイトのデータで Base64 でエンコードされます。この方法を利用する場合、まず送信側がこれらの情報からパスワードのダイジェストを作成します。受信側では、プレーンテキストで保管されているパスワードを取得してハッシュを行い、ダイジェストを作成しなおします。結果が一致すれば、送信されたパスワードが正しかったことになります。このやり方では、リプレイ攻撃からは保護されません。この方法を利用する場合は、必ず wsu:Timestamp 要素を併用して、有効期間を短く設定します。さらに、その wsu:Timestamp 要素に署名してタイムスタンプの改ざんを発見できるようにします。このように正しく利用しないと、悪意の攻撃者が正しい UsernameToken を抜き出してWebサービスに攻撃を仕掛けることができてしまいます。リプレイ攻撃から Web サービスを守るには、受信したメッセージを一意に識別できる特徴のようなものを、メッセージの有効期間中にキャッシュに保管して、追跡できるメカニズムが必要です。

X.509 証明書

X.509 証明書を送信することでユーザーを認証する方法もあります。X.509 証明書はユーザーが誰であるのかを受信側に伝達します。PKI を利用すれば、証明書をアプリケーションの既存ユーザーにマッピングすることも可能です。証明書だけを利用する方法では、簡単にリプレイ攻撃の対象になってしまうので、送信側は秘密キーを使ってメッセージに署名しておかなければなりません。メッセージの署名が検証できれば、送信者が本当にそのユーザーであることが確認できます。

メッセージに X.509 証明書も含むときは、WS-Security で定義されている BinarySecurityToken に公開している証明書を設定します。証明書自体はBase64でエンコードされたデータとして送信されます。BinarySecurityToken のスキーマは次のとおりです。

<xs:element name="BinarySecurityToken">
    <xs:complexType>
        <xs:simpleContent>
            <xs:extension base="xs:string">
                <xs:attribute name="Id" type="xs:ID" />
                <xs:attribute name="ValueType" type="xs:QName" />
                <xs:attribute name="EncodingType" type="xs:QName" />
                <xs:anyAttribute namespace="##other" 
                    processContents="strict" />
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>
</xs:element>

基本的に、この要素には文字列とユニークな ID、それにどんなデータがどのようにエンコードされているかを示す情報が含まれます。ValueType 属性には以下の値のどれかを設定できます。これらの値は、WS-Security のスキーマの中で ValueTypeEnum として定義されています。

  • wsse:X509v3: An X.509, version 3 証明書
  • wsse:Kerberosv5TGT: Kerberos 仕様のセクション 5.3.1 で定義されているチケット認可チケット
  • wsse:Kerberosv5ST: Kerberos 仕様のセクション 5.3.1 で定義されているサービスチケット

Kerberos については次のセクションで解説します。 EncodingType には、wsse:Base64Binary か wsse:HexBinary を指定できます。この値は単にエンコーディング方式を示すだけです。WS-Security ヘッダーでX.509証明書を送信する例は次のとおりです。

<wsse:BinarySecurityToken 
    ValueType="wsse:X509v3" 
    EncodingType="wsse:Base64Binary" 
    Id="SecurityToken-f49bd662-59a0-401a-ab23-1aa12764184f"
>MIIHdjCCB...</wsse:BinarySecurityToken>

X.509 証明書を利用するときは、メッセージに署名するなどの別の方法もあわせて利用することを忘れないでください。証明書に関連付けられた秘密キーで作成された署名を使えば、クライアントが証明書の正規の所有者であることを確認できます。しかし、この方法ではリプレイ攻撃は防げないので、メッセージの有効期間を決める別の仕組みも併用する必要があります。有効期間などの時間を送受信するために、SOAP メッセージのヘッダーに wsu:Timestamp 要素を含めることができます。

Kerberos

Kerberos を利用するときは、ユーザーはユーザー名とパスワードの組みや X.509 証明書などのクレデンシャルを提示します。すべてが確認できた場合、ユーザーはシステムからチケット認可チケット(TGT)を受け取ります。TGT は単なるデータで、ユーザーは中身を見ることができません。ユーザーは、TGT をそのままの形でアクセス先のリソースに提示します。TGT を提示するのは、普通サービスチケットを取得するためです。これは次のような仕組みになっています。

  1. クライアントはキー配布センター(KDC)で認証を受けて、TGT を取得します。
  2. クライアントはTGTを使ってチケット認可サービス (TGS)にアクセスします。
  3. クライアントは特定のネットワークリソースに対する ST を要求します。TGS が ST をクライアントに発行します。
  4. クライアントは ST をネットワークリソースに提示して、ST に記述されている権限の範囲内でリソースにアクセスします。

Kerberos のメリットは、サービスがクライアントを認証し、クライアントがサービスを認証するメカニズムを提供していることです。ST はあるネットワークリソースに対してのみ有効で、送信者を判別するためにも利用できます。メッセージに Kerberos のチケットも含める場合、そのデータは何も加工せずにメッセージに埋め込まなければなりません。WS-Security では、TGT や ST をどのように取得するかについては特に定義しません。

署名

メッセージが署名されると、メッセージを改ざんすることはほぼ不可能になります。メッセージに署名をしても、外部から内容が見られなくなるわけではありません。署名を使えば、転送途中でメッセージに変更がないことを、SOAP メッセージの受信側で確認できます。XML署名仕様を使えば、署名にまつわる多くの困難な問題がすでに解決されているので便利です。WS-Security では、メッセージが変わっていないことを確認する方法を説明しているだけですが、上記の 3 つの認証メカニズムを使えばメッセージに署名をすることができます。これによって 2 つのことが確認できます。

  • X.509 証明書や UsernamtToken、Kerberos のチケットに記述されているユーザーがメッセージに署名をしたこと
  • メッセージは署名された後に改ざんされていないこと

3 つのメカニズムではどれでも、メッセージに署名するための秘密情報を利用できるようになっています。X.509 では秘密キーを使ってメッセージに署名できます。Kerberos では、送信側がセッションキーを作成して、チケットに含めることができます。メッセージのあて先だけがチケットを読み取ってセッションキーを取り出し、署名を検証することができます。また、UsernameToken ではパスワードを使って署名できます。

署名は XML 署名を利用して生成されます。wsu:Timestamp 要素に署名するときには注意が必要になります。中継局が wsu:Received 要素を追加する可能性があるからです。要素が変更される度に、署名も更新されなければおかしなことになってしまいます。内容が変われば署名の検証に失敗するからです。署名を行い、それに必要なデータを SOAP メッセージに含めると、メッセージにかなり多くの情報が追加されます。どのような追加情報が含まれているのか、あるいはそもそもwsse:Securityヘッダーはどのようになるのかを確認したい場合は、Using WS-Security with the Web Services Development Kit Technology Preview という記事の最後に示されているメッセージを参照してください。

暗号化

メッセージの送信者を認証したり、メッセージが改ざんされていないことが確認できるだけでは不十分なこともあります。クレジットカード番号や銀行口座番号を署名した上でプレーンテキストで送信すると、自分以外の他の攻撃者がメッセージの内容を改ざんしていないことを、悪意の攻撃者も確認できてしまうのです。その結果、データが正しいことを攻撃者が確認できることになります。これでは都合が悪いでしょう。このようなときには、メッセージの正しい受信者だけがメッセージを読むことができるように、メッセージを暗号化します。ネットワークをのぞき見している人間には、メッセージの内容は分からないようにするのです。メッセージの署名と同様、暗号化についても WS-Security は既存の標準を利用するようになっています。既存の標準とは、XML暗号仕様です。

データを暗号化するための方法として、対称アルゴリズムと非対称アルゴリズムがあります。対称アルゴリズムを利用するには、ある秘密を共有する必要があります。つまり、メッセージの暗号化に使ったキーと同じキーを用いて復号も行うのです。送信側と受信側の両方を管理することができて、暗号用のキーを利用する人間やアプリケーションが信頼できる場合には、対称アルゴリズムが効率的です。対称アルゴリズムには、キーの配布という問題が存在します。やり取りを始める前のどこかのタイミングで、受信側にキーを渡さなければなりません。たとえばディスクにコピーして送る方法があります。必要になったときにネゴシエーションを行うこともできるでしょう。

キーの配布を簡単に行いたいのなら、非対称アルゴリズムを利用する方法があります。X.509 証明書を使えば、非対称アルゴリズムで暗号化を行うことができます。受信側が証明書を公開しておけば、誰もがその公開キーを使ってデータを暗号化できます。秘密キーを知る必要があるのは受信側だけです。受信側は秘密キーを使ってデータを復号し、意味ある中身を取り出すことができます。

メッセージを暗号化するとどのように見えるようになるのでしょうか。WS-Security を使って、XML 暗号仕様で暗号化したデータを埋め込んだメッセージは、次のようなものになります。対称アルゴリズムの1つであるトリプル DES を利用しているので、送信側と受信側があらかじめ、キーは Kerberos のチケットに隠したり、メッセージの送受信とは別の場所で交換するなどして、共有しておく必要があります。

<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope 
    xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <soap:Header    
        xmlns:wsse="https://schemas.xmlsoap.org/ws/2002/07/secext"
        xmlns:wsu="https://schemas.xmlsoap.org/ws/2002/07/utility">
        <wsu:Timestamp>
            <wsu:Created 
                wsu:Id="Id-3beeb885-16a4-4b65-b14c-0cfe6ad26800"
                >2002-08-22T00:26:15Z</wsu:Created>
            <wsu:Expires 
                wsu:Id="Id-10c46143-cb53-4a8e-9e83-ef374e40aa54"
                >2002-08-22T00:31:15Z</wsu:Expires>
        </wsu:Timestamp>
        <wsse:Security soap:mustUnderstand="1" >
            <xenc:ReferenceList>
                <xenc:DataReference 
        URI="#EncryptedContent-f6f50b24-3458-41d3-aac4-390f476f2e51" />
            </xenc:ReferenceList>
            <xenc:ReferenceList>
                <xenc:DataReference 
        URI="#EncryptedContent-666b184a-a388-46cc-a9e3-06583b9d43b6" />
            </xenc:ReferenceList>
        </wsse:Security>
    </soap:Header>
    <soap:Body>
        <xenc:EncryptedData 
            Id="EncryptedContent-f6f50b24-3458-41d3-aac4-390f476f2e51" 
            Type="http://www.w3.org/2001/04/xmlenc#Content">
            <xenc:EncryptionMethod Algorithm=
                "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                <KeyName>Symmetric Key</KeyName>
            </KeyInfo>
            <xenc:CipherData>
                <xenc:CipherValue
                >InmSSXQcBV5UiT...  Y7RVZQqnPpZYMg==</xenc:CipherValue>
            </xenc:CipherData>
        </xenc:EncryptedData>
    </soap:Body>
</soap:Envelope>

上記のメッセージには、暗号化されているデータについての情報と、暗号化を行った方法についての情報が含まれています。キーを持っていないと、soap:Body 要素の中にある暗号化データを復号することはできません。

非対称アルゴリズムで暗号化を行う場合は、メッセージの受信側だけが秘密キーを知っていれば、メッセージを復号できます。公開キーはあらかじめ公開されている必要があります。

まとめ

WS-Security によって、SOAP メッセージの送信者を認証したり、SOAP メッセージに署名したり、SOAP メッセージの内容を暗号化することができます。WS-Security では、SOAP メッセージのセキュリティを確保するために既存の仕様を再利用して、可能な限り新しい技術を必要としないようにしています。すべての情報がメッセージ自体に含まれているので、メッセージは転送プロトコルを選びません。HTTP で送信されても、電子メールで送信されても、CD-ROM で運ばれても、いずれの場合も安全に渡すことができます。

関連情報