日向夏特殊応援部隊

俺様向けメモ

OpenID Provider のセキュリティ対策 (1) - まずは SSL を導入!話はそれからだ

やっと下準備終わったので書いてみる。

OpenID でのプトロコルメッセージで、認証アサーション要求*1及び応答*2でのメッセージは通常、RP-OP 間で associate 時に交換した MAC キーを持って署名を行う為、期待する相手と通信している限りは改ざんは起こりにくいと考えられます。

但し最近話題に出て来ている DNS Cache Poisoning のような攻撃を受けた場合、中間者攻撃 (man-in-the-middle attack) が成立する可能性があります。

攻撃手法の例

例えば、RP の DNS が汚染されていた場合を考えます。本来 OP であるはずのホストが悪意のある第三者のサーバーに割り当てられていた場合、その第三者のサーバーが中継を行えば、DH 鍵交換を行ってもまったく無意味で、認証データが盗まれる可能性があります。つまり、

  • RP から見ると OP に見えて
  • OP から見ると RP に見える

ような RP Proxy をでっち上げると、問題無く associate を行い、間のデータは全てすっぱ抜かれると。

SSL/TLS を用いた場合

この場合は SSL/TLS の機構を信じる事が出来る、つまり信頼出来る認証局が発行したサーバー証明書の場合は、認証アサーション要求/応答メッセージの改ざんは難しいのでこれを採用し、DH 鍵交換ではなく平文で MAC キーを渡すようにすれば良いと思います。

また associate や check_authentication の場合は署名はありませんので、より中間者攻撃のリスクが高まります。ここでもやっぱり SSL/TLS 使おうって話になってしまうと。

この際に、オレオレ証明書だったりとか、サーバー証明書の発行基準がだいぶグレーな認証局とかは弾きたいので、d:id:ZIGOROu:20080805:1217923189 のような確認手法が必要になります。今まで LWPx::ParanoidAgent 使ってるから大丈夫とか思ってたかもしれませんが大きな間違えです!

一応 LWPx::ParanoidAgent には paranoid_proxy と言う設定項目があり、

if (my $pp = $self->{paranoid_proxy}) {
    $req->uri("$pp?url="   . eurl($req->uri) .
              "&timeout="  . ($self->{timeout}  + 0) .
              "&max_size=" . ($self->{max_size} + 0));
}

と言う形式で Proxy (的なもの!?) 経由でアクセス出来るようなインターフェースがありますが、まぁリスクを減らす事は出来ますが解決策にはなってないので、やはり SSL/TLS を使うべきです。

ちなみにOpenID Authentication 2.0 仕様にもきちんと書いてあります。

In order to get protection from SSL, SSL must be used for all parts of the interaction, including interaction with the end user through the User-Agent. While the protocol does not require SSL be used, its use is strongly RECOMMENDED.
簡単に言えば、
UA を介した通信も含めて全ての双方向通信で SSL を使った方がいいですよ
って事ですね。

国内 OP の現状

2008/08/05 現在の国内OPの対応状況。
はてな
ZIGOROu - はてな より、
<link rel="openid.server" href="http://www.hatena.ne.jp/openid/server" />
なので SSL 非対応。
Livedoor
livedoor プロフィール より、
<link rel="openid.server" href="http://auth.livedoor.com/openid/server" />
<link rel="openid2.provider" href="http://auth.livedoor.com/openid/server" />
<meta http-equiv="x-xrds-location" content="http://auth.livedoor.com/openid/xrds?username=zigorou_" />
なので SSL 非対応。 部分的に対応しているようです。 対応してくれたお! 以下追記分(2008-08-19T00:11:58+09:00)。 再び OP-Local Identifier のHTMLを見てみると、上記の物と現段階では変わっていません。
$ lwp-request -m HEAD http://profile.livedoor.com/zigorou_/
のようにやると、
X-XRDS-Location: http://auth.livedoor.com/openid/xrds?username=zigorou_
と返って来る。
$ curl http://auth.livedoor.com/openid/xrds?username=zigorou_
とすると、
<?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="1">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <URI>https://auth.livedoor.com/openid/server</URI>
      <LocalID>http://profile.livedoor.com/zigorou_/</LocalID>
    </Service>
    <Service priority="2">
      <Type>http://openid.net/signon/1.1</Type>
      <URI>https://auth.livedoor.com/openid/server</URI>
      <openid:Delegate>http://profile.livedoor.com/zigorou_/</openid:Delegate>
    </Service>
    <Service priority="3">
      <Type>http://openid.net/signon/1.0</Type>
      <URI>https://auth.livedoor.com/openid/server</URI>
      <openid:Delegate>http://profile.livedoor.com/zigorou_/</openid:Delegate>
    </Service>
    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <URI>http://auth.livedoor.com/openid/server</URI>
      <LocalID>http://profile.livedoor.com/zigorou_/</LocalID>
    </Service>
    <Service priority="20">
      <Type>http://openid.net/signon/1.1</Type>
      <URI>http://auth.livedoor.com/openid/server</URI>
      <openid:Delegate>http://profile.livedoor.com/zigorou_/</openid:Delegate>
    </Service>
    <Service priority="30">
      <Type>http://openid.net/signon/1.0</Type>
      <URI>http://auth.livedoor.com/openid/server</URI>
      <openid:Delegate>http://profile.livedoor.com/zigorou_/</openid:Delegate>
    </Service>
  </XRD>
</xrds:XRDS>
と返って来る。対応して欲しいなと思うのは、
  • HEAD時のレスポンスヘッダ X-XRDS-Location 及び HTML 中の x-xrds-location の値を https にする
かな。openid.server, openid2.provider の値は delegate で使われている可能性もあるので後方互換性の為にそのままにしておくのが良さそうです。 (さらに追記 2008-08-19T12:01:41+09:00) 中の人が対応してくれたみたいです!livedoor++
wassr.jp
ちゃっかり OP な wassr も確認。http://wassr.jp/user/zigorou より
<link rel="openid2.provider" href="https://wassr.jp/open_id/auth" />
<link rel="openid.server" href="https://wassr.jp/open_id/auth" />
なので SSL 非対応。 SSL 対応したようです。中の人 GJ すぐる!
OpenID.ne.jp
http://zigorou.openid.ne.jp/ より、
<link rel="openid.server" href="http://zigorou.openid.ne.jp/index.php/serve" />
<link rel="openid.delegate" href="http://zigorou.openid.ne.jp/" />
なので SSL 非対応。ところで何故 delegate 指定してあるんだw
Yahoo! JAPAN
https://me.yahoo.co.jp/a/dLJv9AJ6Zftj.zOQocdM_hEdqg-- より、
<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">
SSL に対応済み。さすが Yahoo! ですね。

まとめ

特別な理由が無い限り、OP Endpoint URL や XRDS など、OP が提供する情報には SSL/TLS を適用しましょう。 さらに言えば RP も提供する return_to URL なども SSL/TLS を適用する事をお勧めします。

*1:checkid_setup, checkid_immediate

*2:id_res,setup_needed,cancel