VOXのSCRIPT対応とユーザ認証用クッキーのドメイン

マッシュアップ、という言葉が現れる前からSCRIPTタグを使ってブログを飾るさまざまなブログパーツがありました。最近では、アマゾンの Amazonおまかせリンク や Google Analytics のように企業が提供するツールでもHTMLの中からSCRIPTタグで読み込んで利用することが増えています。

クッキーの問題

そういったブログパーツを利用するためには、使用しているブログサービスが、エントリの本文やブログのサイドバーなどにSCRIPTタグを入れることを許可している必要があります。しかし、ページの中に任意のスクリプトを書けるようにすると、クッキーを発行するドメインを別にする等の対策をしなければ、同じブログサービスを利用しているユーザがそのページを閲覧したときに認証用のクッキーを盗み出せるようになってしまいます。

そこでSCRIPTタグを利用できるブログサービスが、このクッキー盗難問題にどう対処しているかを調べてみました。

ヤプログ!

ヤプログ!の場合、ブログの管理画面はすべて www.yaplog.jp ドメインに集められており、ユーザ認証用に発行されるクッキーのドメインは www.yaplog.jp になっています。ブログが表示されるドメインは yaplog.jp なので、認証用のクッキーの内容はサーバに送信されません。そのため、スクリプトからログインクッキーを読み取ることはできません。

この方法はドメインを変更するだけなので容易に実現できますが、デメリットもあります。ブログを閲覧するときには認証用のクッキーの内容がサーバに送信されないため、ユーザがログインしているかどうかを表示することができません。そんなに不便なことはありませんが、エントリにコメントする時などに名前を入力してもらうことになります。

livedoor ブログ

livedoor ブログ もヤプログと同様のアプローチをとっているようです。livedoorにログインすると livedoor.com ドメインでクッキーが発行されます。ブログの管理画面は cms.blog.livedoor.com にあるのでログインしたときのクッキーで認証が行われます。 ブログの閲覧するときは livedoor.jp, livedoor.biz など livedoor.com 以外のドメインになっているため、スクリプトでログインクッキーを読み出すことはできません。

管理画面と閲覧するページとでドメインを変えてクッキーを読み取られないようにしているため、ヤプログ!と同様ログイン状態の表示はなく、コメント投稿時には名前を入力する必要があります。

VOX

VOX でSCRIPTタグが入力できるようになったというのは VOX now allows you to post arbitrary HTML -- including JavaScript! - 404 Web 2.0 Not Found で知りました。

VOXは、ユーザの認証が必要なページは www.vox.com に置かれ、ユーザの投稿などを閲覧するページは userid.vox.com に置かれています。一見すると上述したヤプログ!や livedoor ブログとおなじアプローチをとっているように思えます。しかし、VOXは userid.vox.com にあるユーザのページを閲覧しているときでもログイン状態をサーバが知っていて、右上にログインしているユーザ名を表示しているので、何らかの方法でサーバにログインしていることを知らせています。
Vox Beta Testing: Embedding - Team Voxそこで、どういうしくみでログインクッキーの安全性を保ちつつSCRIPTタグを利用可能にしているのか調べました。

VOXのログインクッキー

http://www.vox.com/signin/save にユーザ名とパスワードをPOSTしてログインすると、セッション管理用に3つのクッキーが発行されます。
AID
domain=www.vox.com
UAID
domain=www.vox.com
CometBiscuit
domain=vox.com
このクッキーは中に E=mc2 がエスケープされて入っていました。はじめ Comet に関連した何かかと思いましたが違うようです。Cometでビスケットでアインシュタイン。何か関係あるのでしょうか?
詳細はわかりませんが、AIDとUIDでユーザを識別しているようです。このふたつは www.vox.com ドメインに対して発行されています。もうひとつの ComentBiscuit は vox.com ドメインで発行されています。 はじめ、www.vox.comのホストから domain=vox.com でクッキーが発行できることを知りませんでした。クッキーのドメインとその有効性と、送られる先については、おさかなラボ - MixiとCookieドメイン によれば明確なしようがないそうですが、実装がどうなっているかは Cookie(クッキー)の届く範囲 に詳しい実験の結果が掲載されていました。(ただし実験に使用されているブラウザは不明です) 実験結果から www.vox.com で domain=vox.com のクッキーが発行可能、というのも心細いので調べたところ obsolete ながらも RFC2109 の中に、クライアントはこんな場合にクッキーを捨てるべし、という記述を発見しました。
4.3.2 Rejecting Cookies To prevent possible security or privacy violations, a user agent rejects a cookie (shall not store its information) if any of the following is true: (3つ省略) * The request-host is a FQDN (not IP address) and has the form HD, where D is the value of the Domain attribute, and H is a string that contains one or more dots. Examples: * A Set-Cookie from request-host y.x.foo.com for Domain=.foo.com would be rejected, because H is y.x and contains a dot. * A Set-Cookie from request-host x.foo.com for Domain=.foo.com would be accepted.

クライアントからリクエストを受けたホストがFQDNを持っていて、そのかたちが $H$D という文字列で表せるとしたとき、$Dがクッキーで指定されたdomainで$Hがそれ以外の部分だったときに、$Hがドットを含んでいてはいけない、ということみたいです。
文章だとわからないのでVOXを例に書くと www.vox.com で domain=vox.com のクッキーを発行する場合、ここがまたややこしいですがRFC2109ではdomainの先頭に必ず . をつけることになっているので、アタマに . をつけて $D = .vox.com として考えると $H
はホスト名の残りの部分なので $H = www になり、ドットが含まれていないので受け取ってもらえる、ということになります。
この解釈の仕方は上のページの実験結果と一致しているので、クッキーを受け取るドメインの取捨選択部分はある程度RFC2109に従っているのかもしれません。

ユーザのページでもクッキーが発行される

VOXでログインした後、個々のユーザのページ userid.vox.com にアクセスすると、裏側ではいろいろあるのですが、見たかんじは何もないままで右上にログインしていることを表す自分のプロフィール画像が表示されます。
ログイン後に発行されたクッキーのうち、このドメイン userid.vox.com に送信されるクッキーは E=mc2 が入っているだけのCometBiscuitしかありません。内容は固定なのでどうがんばってもユーザの識別には使えません。

livehttpheaders でリクエストを観察すると、ユーザのページにアクセスしたときにVOXはこのCometBiscuitがあるかないかをチェックし、ある場合は
Location: http://www.vox.com/sitelogin?uri=http://userid.vox.com/&fp=(1024bitの値)
にリダイレクトしていました。そしてリダイレクトされた先でもすぐにリダイレクトされて
http://userid.vox.com:80/services/sitelogin?uri=http://userid.vox.com/&token=(108文字のトークン)
userid.vox.com に戻ってきます。そしてこのページで
Set-Cookie: VID=(token=で渡された108文字のトークン); domain=userid.vox.com; path=/
userid.vox.com のドメインでクッキーが発行され、ユーザのトップページにリダイレクトされるようになっていました。

流れから判断して
  1. ランダムな値をfpに設定してwww.vox.comにリダイレクト
  2. www.vox.comのログインクッキーからユーザ名を判別してfpをもとにトークンを生成してDBに保存。トークンはユーザ名と結びついている
  3. www.vox.comから渡されたトークンをuserid.vox.comドメインのクッキーで発行
  4. userid.vox.comにアクセスするとトークンが送られてくるので、2で保存したトークンと一致するものを探す
という手のこんだ仕組みになっているのでしょう。

異なるユーザのページを閲覧するごとにこのリダイレクトが発生するので、パフォーマンスの観点からは好ましくありませんが、これでユーザのページが別のドメインになっていても、ログイン状態を表示することが可能になります。

ログアウトしたら?

ですが userid.vox.com で www.vox.com と別にユーザ識別用のクッキーを発行すると www.vox.com でログアウトしても userid.vox.com にアクセスするとログインしたまま、ということにならないのかが気になります。が、ログアウトしたらすべてのユーザのページでもログアウトしている状態になります。 このしくみのカギは domain=vox.com の CometBiscuit で、ログアウトするときにこのクッキーが消去されます。このクッキーはログインクッキーと違ってすべてのユーザのページに送信されるので、このクッキーがあるかないかでVOXはユーザがログインしているかどうかをチェックしているようです。これがない場合は userid.vox.com のクッキーがあったとしても無条件でログインしていないとみなすしくみになっているようです。

クッキーは関係なくてIFRAME

ここまでえんえんVOXのクッキーのドメインの話を書いてきましたが、よく考えるとこのアプローチでも相変わらず userid.vox.com のクッキーを抜き取ってそのユーザに成り済ますことができます。 userid.vox.com でしか有効でないので、新しく記事を書いたり、消したりはできませんが、他人に成り済ましてコメントしたりすることはできます。

どうなっているのだろう、と、実際にSCRIPTタグを入れてみたらすぐにわかりました。
VOXは投稿された内容のうち、SCRIPTタグで囲まれた部分をHTMLの中にそのまま表示せず、そのかわりに別のドメイン a*.vox-data.com にSCRIPTが書かれているだけのHTMLを用意してそのHTMLをIFRAMEで表示するようになっていました。
こうするとユーザのページとスクリプトが読み込まれるページのドメインが異なるのでスクリプトからクッキーを読み出すことはできない状態のままで、任意のスクリプトを実行可能にすることができます。
ページの中身を参照して何かを出力したりするブログパーツは機能しませんし、スクリプトが埋め込まれているURLを参照するようなものも機能しなくなりそうですが、そういったことをしないスクリプトを含めて全く入れられないところからは一歩前進することができます。

エントリにスクリプトを入れるには

本題とは関係ありませんが、エントリにスクリプトを入れる方法も書いておきます。Vox Beta Testing: Embedding - Team Vox と Vox Knowledge Base: Testing new Vox features を読めば書いてあるのですが、何も読まずにタグ書けばいいんでしょと始めてつまずいたので.... アカウント設定 - Vox のページで"新機能テストに参加する"
をチェックして、投稿画面で "コード挿入" ボタンを押すと出てくるウインドウで <script>....</script> と、ふつうにコードを書けばOKです。<script>だけでなく<embed>なども入れられるようになったみたいです。

まとめ

ログインクッキーの安全性を保ちつつ、ユーザのページに任意のスクリプトを埋め込めるようにするにはドメインを分けるのが一般的でした。しかしこの方法ではユーザのページを閲覧しているときにユーザのログイン状態を識別することができなくなります。

VOXは、ユーザのページと管理ページと両方に送られる読み取られても問題のないクッキーを利用してログインしているかどうかだけを調べ、ユーザのページで再度そのユーザのページだけで有効な認証用のクッキーを発行するためのインターフェイスを用意することで、ログイン状態を表示できるようにしていました。しかし、この方法ではクッキーを盗まれたときの被害を小さくすることができますが、盗まれることを防止することはできません。

VOXはSCRIPTタグの内容を別ファイルにして、異なるドメインに置いたHTMLから読み込み、そのHTMLをIFRAMEでページに埋め込むことで任意のスクリプトを安全に実行できるようにしていました。このアプローチですべてのスクリプトが機能するわけではありませんが、正しく機能するスクリプトもあるでしょうから、セキュリティと利便性の落としどころのひとつとして知っていて損はなさそうです。

tags

  • HTML
  • 「VOXのSCRIPT対応とユーザ認証用クッキーのドメイン」のはてなブックマーク数
  • 「VOXのSCRIPT対応とユーザ認証用クッキーのドメイン」deliciousブックマーク数
  • 「VOXのSCRIPT対応とユーザ認証用クッキーのドメイン」をはてなブックマークに追加
  • save "VOXのSCRIPT対応とユーザ認証用クッキーのドメイン" to del.icio.us
  • 「VOXのSCRIPT対応とユーザ認証用クッキーのドメイン」をリアルタイムブログ検索
  • permalink
  • vim.org にある tips からみつけた目が覚めるようなコマンド
  • ファイルの先頭8バイトだけで画像のフォーマットを調べる

comments

TypeKey Enabled
スタイル用のHTMLタグが使えます。
*required
butcher
2007.05.17 14:21

ご苦労様です。すごいわかりやすい!

Favicon for http://p0t.jp/mt/komagata
2007.05.18 12:46

なるほど~

trackbacks

トラックバック元エントリにこのエントリへのリンクがない場合はトラックバックを受け付けません。

http://labs.gmo.jp/mt/mt-tb.cgi/125
©2010 Kentaro Kumagai, GMO Internet Labs., GMO Internet, inc.
bits and bytes
2007 .05. 16 19:28

tagcloud

  • API1
  • C/C++2
  • E4X1
  • FUSE2
  • Firefox18
  • HTML4
  • IE1
  • MySQL1
  • OSX4
  • Opera2
  • PHP4
  • XML1
  • XPCOM4
  • XPath3
  • apache2
  • binary2
  • book1
  • data11
  • debug4
  • design1
  • experiments3
  • extension10
  • google gears1
  • google maps API1
  • greasemonkey3
  • httpd5
  • javascript17
  • linux1
  • logging2
  • mobile3
  • perl4
  • tips4
  • tool11
  • vim2
  • visualization2
  • widget1
  • wii1
  • windows7
  • サービス6
  • 和訳1

Archives

  • 2008.02 (6)
  • 2008.01 (3)
  • 2007.12 (4)
  • 2007.11 (5)
  • 2007.10 (4)
  • 2007.09 (4)
  • 2007.08 (4)
  • 2007.07 (8)
  • 2007.06 (7)
  • 2007.05 (4)
  • 2007.04 (5)
  • 2007.03 (6)
  • 2007.02 (4)
  • 2007.01 (6)

about

  • bits and bytesのXML
  • 「bits and bytes」のCreative Commons
  • Powered by Movable Type
  • イベントと地図 - モグ
  • Use ecto to blog!
  • bits and bytesのはてなブックマーク数
  • bits and bytesをMy Yahoo!に追加
  • Subscribe with Bloglines