• OpenID認証2.0の"概論"についての発表資料です
  • 仕様の詳細部分については説明を省略しています
  • XRI周辺についての説明も省略しています(力量不足につき)
  • 仕様を把握しきれてはいないため、誤りが多く含まれている可能性があります

以下は、実際の発表で使用したスライドのPDFです。
- 発表資料(PDF) -- 1.1MB

  • はじめに
  • OpenID認証とは
  • 特徴
    • 「オープン」
    • 「秘密情報の保護」
    • 「分散的」
    • 「HTTP」
    • 「拡張」
  • 用語
  • プロトコル概観
    • 開始(Initiation)
    • 正規化(Normarization)
    • 発見(Discovery)
    • 関連づけ(Association)
    • 認証要求
    • エンドユーザーの認可
    • 承認/却下
    • 照合
  • 実例
    • OP-Local Identifierで始める
    • OP Identifierで始める
    • HTMLのURLで始める
    • 自前のYadis IDで始める
  • セキュリティ
    • 攻撃の予防
    • 盗聴による攻撃
    • 中間者による攻撃
    • 悪意のRPによるProxy攻撃
    • User-Agent
    • UI
    • DoS攻撃
    • 信頼性と評価
  • おまけ
    • 参照先
    • OPとRPの一例
    • OP
    • RP
    • 日本での活動
    • 手前味噌
  • 最後に

はじめに

  • OpenID認証2.0の"概論"についての発表資料です
  • 仕様の詳細部分については説明を省略しています
  • XRI周辺についての説明も省略しています(力量不足につき)
  • 仕様を把握しきれてはいないため、誤りが多く含まれている可能性があります
  • 誤りの訂正や、内容へのご批判等、コメントやメール等でご指摘お願いします
    • suzuki at feedforce.jp

以下は、実際の発表で使用したスライドのPDFです。
- 発表資料(PDF) -- 1.1MB

OpenID認証とは

OpenID認証はエンドユーザーが管理するIdentifierを証明する方法を提供します。

注目
  • Identifierはエンドユーザーが管理している

特徴

「オープン」

公開規格である為、誰にでも自由に無償で利用可能です。当然ながら、アイデンティティを特定ドメインに限定せず、Web全体での利用を可能にします。

また、公開規格である事から、ドメイン間を統一的な認証インターフェースで繋ぐ効果が期待できます。例えば、(擬似的な)SSOが考えられるでしょう。

注) 実際に安全なSSOの実現が簡単であるかは別問題とします。

「秘密情報の保護」

OpenID認証では、認証を要求する側に対して、エンドユーザーのパスワードやメールアドレスなどを教える事無く、認証を完了させる事が可能です。

「分散的」

OpenID認証では、中央の権威機関などが存在しない為、分散的であると言えます。つまり、特別な機関の承認や登録を必要としません。

また、エンドユーザーは利用する認証のサーバーを自由に選択する事が出来ます。認証のサーバーを切り替えたとしても、利用しているアイデンティティを保持する事が可能です。

「HTTP」

OpenID認証では、標準的なHTTPのリクエスト/レスポンスのみを使います。このため、User-Agentの特別な能力や、その他の特別なクライアントソフトウェアが要求される事はありません。例えば、認証の手続きの間に、Cookieの利用が強制される様な事もありません。

HTTPベースであるため、AJAXスタイルでもうまくいきますが、この場合は、モダンブラウザやスクリプト対応などに依存する事になります。

「拡張」

OpenID認証では、認証以上の事を拡張仕様で補う様になっています。例えば、プロフィール情報の交換や、その他のアイデンティティに基づく情報の交換等が、拡張しようを利用して行われます。

また、認証のサーバーのポリシーを取得する為の拡張しようなども提案されているようです。

用語

沢山のIdentifierが登場する為、ここで全てを理解するのは難しいと思います。後述するプロトコル概観の中で、つじつまを合わせるのが良いでしょう。

Identifier

いわゆるアイデンティティです。個人を特定する記号であると考えればよいでしょう。HTTPかHTTPSをスキームとするURIか、XRIで表現されます。

OpenID認証のドキュメント中には、文脈によった様々なIdentifierが登場するので、注意してください。

User-Agent

HTTP/1.1を実装しているエンドユーザーのウェブブラウザです。ウェブブラウザに限定するわけでもありませんが、対話的な認証を行う場合は、一般的にウェブブラウザが使われるでしょう。

Relying Party

RPと呼びます。エンドユーザーが管理するIdentifierの証明を望むウェブアプリケーションの事です。

OpenID Provider

OPと呼びます。RPがエンドユーザーの管理するIdentifierを主張するために信頼するOpenID認証サーバーです。

OP Endpoint URL

User-Supplied Identifierに対して発見を行った結果に得られた、OpenID認証プトロコルのメッセージを受け取るURLです。これは、HTTPかHTTPSの絶対URLです。

OP Identifier

OPを表すIdentifierです。例えば、Yahoo! JAPANの場合、"http://yahoo.co.jp/"であると考えてよいでしょう。

User-Supplied Identifier

エンドユーザーによってRPに与えられるIdentifierか、OPでエンドユーザーに選択されるIdentifierの事です。

Claimed Identifier

エンドユーザーが自分のものであると主張するIdentifierです。OpenID認証は、この主張が真実である事を証明する事を目的としています。

User-Supplied IdentifierがURLだった場合はそれを正規化して得られたIdentifierで、XRIだった場合はCanonicalIDです。

OP-Local Identifier

各OPで局所的な、エンドユーザーの為の代替Identifierです。これは、エンドユーザーの管理下にある必要はありません。

プロトコル概観

概観について、一部、実例を交えながら説明します。
- OP: Yahoo! JAPAN
- RP: Fastladder

開始(Initiation)

エンドユーザーが、User-Agent経由でRPにUser-Supplied Identifierを与えます。

開始

正規化(Normarization)

RPは、受け取ったUser-Supplied Identifierを正規化します。

yahoo.co.jp -> http://yahoo.co.jp/

発見(Discovery)

正規化したUser-Supplied Identifierに対して、発見を行います。

発見の結果、エンドユーザーの認証に使う"OP Endpoint URL"が確立されます。

$ curl -I http://yahoo.co.jp/
HTTP/1.1 302 Found
Date: Mon, 18 Feb 2008 14:08:03 GMT
Location: http://www.yahoo.co.jp/index.html
Connection: close
Content-Type: text/html; charset=euc-jp
  • リダイレクトがある場合は追いかけます
$ curl -I http://www.yahoo.co.jp/index.html
HTTP/1.1 200 OK
Date: Mon, 18 Feb 2008 14:08:23 GMT
P3P: policyref="http://privacy.yahoo.co.jp/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"
Expires: -1
Pragma: no-cache
Cache-Control: no-cache
X-XRDS-Location: http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds
Connection: close
Content-Type: text/html; charset=utf-8
  • 詳細は省略しますが、"X-XRDS-Location"のURLからドキュメントを取得します
$ curl -i http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds
HTTP/1.1 200 OK
Date: Mon, 18 Feb 2008 14:10:51 GMT
P3P: policyref="http://privacy.yahoo.co.jp/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"Last-Modified: Thu, 17 Jan 2008 01:25:25 GMT
Accept-Ranges: bytes
Content-Length: 354
Connection: close
Content-Type: application/xrds+xml

<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS
    xmlns:xrds="xri://$xrds"
    xmlns:openid="http://openid.net/xmlns/1.0"
    xmlns="xri://$xrd*($v*2.0)">
  <XRD>
    <Service priority="0">
      <Type>http://specs.openid.net/auth/2.0/server</Type>

 <URI>https://open.login.yahooapis.jp/openid/op/auth</URI>
    </Service>
  </XRD>
</xrds:XRDS>
  • URI要素でOP Endpoint URLが示されています。

関連づけ(Association)

このプロセスは任意です。

OpenID認証の手続きの中で、RPとOPはリクエスト/レスポンスの署名を確認する事で、それぞれの正当性を証明します(照合(Verification))。

関連づけは、この照合のための余計なリクエスト/レスポンスを節約する為に役立ちます。

具体的には、Diffie-Hellman鍵共有を利用して、RPとOPの間に関連付けを構築します。
- Diffie-Hellman鍵共有 - Wikipedia

認証要求

RPがエンドユーザーのUser-Agentを、認証要求パラメータをつけた"OP Endpoint URL"にリダイレクトさせます。

認証要求のパラメータ例
  • openid.ns
  • openid.mode
  • openid.claimed_id
  • openid.identity
  • openid.assoc_handle
  • openid.return_to
  • openid.realm

パラメータの詳細には触れません。

エンドユーザーの認可

OPが、エンドユーザーが本当にOpenID認証を行うために正当であると認められているのかを確認します。

一般に、これはエンドユーザーをログインさせる事で確かめられます。

この方法や方針については、OpenID認証の仕様の範囲外となっています。

エンドユーザー認可

承認/却下

RPからの認証要求に対して、OPは承認か却下を示すメッセージを付けて、エンドユーザーのUser-AgentをRPにリダイレクトします。

メッセージのパラメータ例
  • openid.ns
  • openid.mode
  • openid.op_endpoint
  • openid.claimed_id
  • openid.identity
  • openid.return_to
  • openid.response_nonce
  • openid.invalidate_handle
  • openid.assoc_handle
  • openid.signed
  • openid.sig

パラメータの詳細には触れません。

照合

OPから受け取った情報について、RPが照合を行います。
- 戻りURL
- 発見した情報
- nonce
- 署名

この照合が全て妥当であったときに、OpenID認証による認証は成功となります。

成功

実例

幾つかの実例を見てみましょう。概観に引き続き、RPはFastladderで、OPはYahoo! JAPANです。

以下の点に注目してみてください。
- 最終的にRPに認識されるアイデンティティ(Identifier)
- 〜Identifier

この実例を通して特に注意してほしい事は、OPを変更した場合でもIdentifierを保持する方法がOpenID認証の中で提供されている、という事です。

また、この実例の中で利用しているOP-Local Identifierは、各自で発行されたものに読み替えてください。

OP-Local Identifierで始める

User-Supplied IdentifierにOP-Local Identifierを使ってみましょう。

  1. まず、フォームの入力欄にYahoo! JAPANで発行されたIDを入力してボタンをクリックします
    1. https://me.yahoo.co.jp/a/Ya\_JyXB8ZPujNdvm8OOHJ837\_LRI7UJll\_\_x
  2. Yahoo! JAPANにリダイレクトされるので、そのままログインします
  3. ログイン後、OpenID認証を継続するか聞かれるので「続ける」ボタンをクリックします
    1. OPによっては、ここでIdentifierを選択する事ができます
  4. Fastladderにリダイレクトされ、認証が成功して完了です

このケースでは、最終的にYahoo! JAPANで発行されたIDが使われます。

$ curl "https://me.yahoo.co.jp/a/Ya_JyXB8ZPujNdvm8OOHJ837_LRI7UJll__x"
<html>
<head>
<title>
OpenID Provider 2.0 -- User's page
</title><link rel="openid2.provider" href="https://open.login.yahooapis.jp/openid/op/auth">
<link rel="openid.server" href="https://open.login.yahooapis.jp/openid/op/1.1/auth">
</head>
<script>window.location.href='http://openid.yahoo.co.jp';</script>

<body>
<p>
The user's OpenID provider is 
<a href="https://open.login.yahooapis.jp/openid/op/auth">
https://open.login.yahooapis.jp/openid/op/auth</a>
</p>
</body>
</html>
  • rel="openid2.provider"があるlink要素で(OpenID認証2.0の)OP Endpoint URLが示されています

OP Identifierで始める

User-Supplied IdentifierにOP Identifierを使います。

  1. まず、フォームの入力欄に"yahoo.co.jp"と入力してボタンをクリックします
  2. Yahoo! JAPANにリダイレクトされるので、そのままログインします
  3. ログイン後、OpenID認証を継続するか聞かれるので「続ける」ボタンをクリックします
  4. Fastladderにリダイレクトされ、認証が成功して完了です

このケースでは、最終的にYahoo! JAPANで発行されたIDが使われます。

注) "yahoo.co.jp"からOpenID認証の手続きを始めるために、Yadisプロトコルが使われています

$ curl -LI http://yahoo.co.jp
HTTP/1.1 302 Found
...
Location: http://www.yahoo.co.jp/index.html
...

HTTP/1.1 200 OK
...
X-XRDS-Location: http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds
...
  • 認証を要求するために必要な情報が書かれたドキュメントがX-XRDS-Locationヘッダで示されています
$ curl -i http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds
HTTP/1.1 200 OK
...
Content-Type: application/xrds+xml

<?xml version="1.0" encoding="UTF-8"?>

<xrds:XRDS
    xmlns:xrds="xri://$xrds"
    xmlns:openid="http://openid.net/xmlns/1.0"
    xmlns="xri://$xrd*($v*2.0)">
  <XRD>
    <Service priority="0">
      <Type>http://specs.openid.net/auth/2.0/server</Type>
      <URI>https://open.login.yahooapis.jp/openid/op/auth</URI>

 </Service>
  </XRD>
</xrds:XRDS>

HTMLのURLで始める

  1. まず、フォームの入力欄に自分で管理するIDを入力してボタンをクリックします
    1. http://id.koshigoe.jp/openid2.html
  2. Yahoo! JAPANにリダイレクトされるので、そのままログインします
  3. ログイン後、OpenID認証を継続するか聞かれるので「続ける」ボタンをクリックします
  4. Fastladderにリダイレクトされ、認証が成功して完了です

このケースでは、最終的に"http://id.koshigoe.jp/openid2.html"がIDとして認識されます。

:http://id.koshigoe.jp/openid2.html:

<html>
<head>
  <link rel="openid2.provider" href="https://open.login.yahooapis.jp/openid/op/auth" />
  <link rel="openid2.local_id" href="https://me.yahoo.co.jp/a/Ya_JyXB8ZPujNdvm8OOHJ837_LRI7UJll__x" />

</head>
<body></body></html>
  • rel="openid2.provider"のlink要素でOP Endpoint URLが示されています
  • rel="openid2.local_id"のlink要素でOP-Local Identifierが示されています

自前のYadis IDで始める

Yadis IDは Yadisプロトコルで定義されます。Yadisプロトコルは、Identifierとそれを扱うサービスおよび用途を提供するプロトコルです。

OpenID認証の場合、OpenID認証で使うIdentifierと、それを証明するOPOP Endpoint URLを提供して貰います。

詳細については省略します。

  1. まず、フォームの入力欄に自分で管理するYadis IDを入力してボタンをクリックします
    1. http://id.koshigoe.jp/
  2. Yahoo! JAPANにリダイレクトされるので、そのままログインします
  3. ログイン後、OpenID認証を継続するか聞かれるので「続ける」ボタンをクリックします
  4. Fastladderにリダイレクトされ、認証が成功して完了です

このケースでは、最終的に"http://id.koshigoe.jp/"がIDとして認識されます。

:http://id.koshigoe.jp/:
- Yadis ID

$ curl -I http://id.koshigoe.jp/
HTTP/1.1 200 OK
...
X-XRDS-Location: http://id.koshigoe.jp/yadis_claimed-identifier.php
...

:http://id.koshigoe.jp/yadis\_claimed-identifier.php:
- Yadis document (XRDS)

$ curl -i http://id.koshigoe.jp/yadis_claimed-identifier.php
HTTP/1.1 200 OK
...
Content-Type: application/xrds+xml

<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">

 <XRD>
    <Service>
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <URI>https://open.login.yahooapis.jp/openid/op/auth</URI>
      <LocalID>https://me.yahoo.co.jp/a/Ya_JyXB8ZPujNdvm8OOHJ837_LRI7UJll__x</LocalID>

 </Service>
  </XRD>
</xrds:XRDS>

セキュリティ

攻撃の予防

盗聴による攻撃

OpenID認証は、盗聴について脆弱である可能性があります。特にnonceを確認しない場合、盗聴者は認証に成功した主張を奪いそれを利用する事が出来ます。TLSやSSLなどのトランスポート層での暗号化や、nonceを確認する様にする事で、盗聴による攻撃を防ぐ事が出来ます。

中間者による攻撃

中間者によって、署名されたフィールドが改ざんされる可能性があります。この改ざんは、関連づけを使う事で防ぐ事が出来ます。関連づけによってRPとOPは鍵を共有します。この鍵なしで署名されたフィールドを変更した場合、MACが壊れるので、その改ざんを防ぐ事が出来ると考えられます。MACに関する扱いやすい攻撃方法は知られていないようです。ただし、MACによる保護の質は、そのMACの無作為性に依存します。

また、DNSやトランスポート層が信頼できない場合、メッセージも信頼できません。この場合、攻撃者がOPを装う事が可能な為、関連付けやステートレスモードによって、攻撃者がメッセージを不正に処理する事が出来ます。

そして、発見に攻撃者が介入できる場合、攻撃者がOPを自由に指定できるためOPを装う必要がなくなります。XRDSドキュメントに関しては、XMLDSIGというデジタル署名を利用する事で改ざんを防ぐ事が出来ます。

SSL通信における中間者攻撃に関しては、信頼される機関が発行する証明書を利用する事で、証明書の偽造が非常に困難になります。

悪意のRPによるProxy攻撃

悪意あるRPによって、OPとUser-Agentとの間にProxyが挟まれる可能性があります。この際、エンドユーザーがOPに対して送信するクレデンシャルを、悪意あるRPがキャプチャする事が可能です。Proxyを排除する複数の方法は存在しますが、ここでは省略します。

User-Agent

OpenID認証とは別に、User-Agentやそのホストコンピュータが、マルウェアやスパイウェアに汚染される可能性があります。これは、OpenID認証のプロトコル内で対応できる範囲を超えています。

UI

OPを模したフィッシングサイトから、エンドユーザーを保護できる作りにすべきです。また、フィッシング攻撃の可能性についてエンドユーザーを教育したり、攻撃を無効化するプラグインの様なものを使わせる様にすべきです。

DoS攻撃

OpenID認証におけるリクエストが本物であるかどうかを、素早く確認する様な仕組みは用意されていない為、DoS攻撃の可能性があります。例えば、関連づけや認証の署名を照合する為のメッセージを、RPが繰り返しリクエストする事で行われるでしょう。

最も危険性が高いものは、関連づけにおけるDiffie-Hellman鍵共有の計算です。RPがパラメータを指定できる為、負荷が高い計算をOPに対して強制する事が可能です。

対抗措置としては、IPベースのレート制限やリクエスト拒否を使う事が出来ます。また、"openid.realm"と"openid.return_to"を基にしたリクエスト拒否を考慮してもよいでしょう。

信頼性と評価

OpenID認証は特別な中央機関を必要としない為、それぞれのRPやOPに関する信頼性が未知数です。現状では、一般に有名な信頼できるであろう企業が提供しているOPのみを許可するRPが多いようです。この問題について、色々と議論がされているようです。

おまけ

参照先

OPとRPの一例

OP

  • Yahoo! JAPAN
  • はてな
  • Livedoor
  • Blogger

RP

  • Fastladder
  • はてな
  • LiveJournal

日本での活動

  • アイデンティティ飲み会
  • Liberty Alliance 技術セミナー
  • openid-ja
  • ブログ記事

手前味噌

最後に

今回の発表では、概論にとどめる為に多くを省略しています。
- XRI
- メッセージのフォーマットなど
- 手続きの詳細部分
- 通信種類(間接通信、直接通信)
- 署名
- 照合
- ほか
- OpenID認証1.1との互換性
- 拡張
- など

今回の発表は、OpenIDの概要をつかんでもらいつつ、周辺の話題に触れてもらう事を目的としています。実際に、OpenID認証を導入しようとしたりする場合には、他の参考資料や仕様書原文をあたる必要があるでしょう。

繰り返しになりますが、個人的に以下の資料がおすすめです。
- OpenIDの仕様と技術 連載インデックス - @IT -
- Final: OpenID Authentication 2.0 - Final

それでは、最後までおつきあいいただき、ありがとうございました。

  • このエントリーをはてなブックマークに追加
Feedforce Developer Blog

新しいブログへ移行しました!こちらもよろしくお願いします。