マッシュアップ、という言葉が現れる前からSCRIPTタグを使ってブログを飾るさまざまなブログパーツがありました。最近では、アマゾンの Amazonおまかせリンク や Google Analytics のように企業が提供するツールでもHTMLの中からSCRIPTタグで読み込んで利用することが増えています。
そこでSCRIPTタグを利用できるブログサービスが、このクッキー盗難問題にどう対処しているかを調べてみました。
www.yaplog.jp ドメインに集められており、ユーザ認証用に発行されるクッキーのドメインは www.yaplog.jp になっています。ブログが表示されるドメインは yaplog.jp なので、認証用のクッキーの内容はサーバに送信されません。そのため、スクリプトからログインクッキーを読み取ることはできません。
この方法はドメインを変更するだけなので容易に実現できますが、デメリットもあります。ブログを閲覧するときには認証用のクッキーの内容がサーバに送信されないため、ユーザがログインしているかどうかを表示することができません。そんなに不便なことはありませんが、エントリにコメントする時などに名前を入力してもらうことになります。
livedoor.com ドメインでクッキーが発行されます。ブログの管理画面は cms.blog.livedoor.com にあるのでログインしたときのクッキーで認証が行われます。
ブログの閲覧するときは livedoor.jp, livedoor.biz など livedoor.com 以外のドメインになっているため、スクリプトでログインクッキーを読み出すことはできません。
管理画面と閲覧するページとでドメインを変えてクッキーを読み取られないようにしているため、ヤプログ!と同様ログイン状態の表示はなく、コメント投稿時には名前を入力する必要があります。
VOXは、ユーザの認証が必要なページは www.vox.com に置かれ、ユーザの投稿などを閲覧するページは userid.vox.com に置かれています。一見すると上述したヤプログ!や livedoor ブログとおなじアプローチをとっているように思えます。しかし、VOXは userid.vox.com にあるユーザのページを閲覧しているときでもログイン状態をサーバが知っていて、右上にログインしているユーザ名を表示しているので、何らかの方法でサーバにログインしていることを知らせています。
Vox Beta Testing: Embedding - Team Voxそこで、どういうしくみでログインクッキーの安全性を保ちつつSCRIPTタグを利用可能にしているのか調べました。
http://www.vox.com/signin/save にユーザ名とパスワードをPOSTしてログインすると、セッション管理用に3つのクッキーが発行されます。
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に従っているのかもしれません。

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 のドメインでクッキーが発行され、ユーザのトップページにリダイレクトされるようになっていました。
fpに設定してwww.vox.comにリダイレクト異なるユーザのページを閲覧するごとにこのリダイレクトが発生するので、パフォーマンスの観点からは好ましくありませんが、これでユーザのページが別のドメインになっていても、ログイン状態を表示することが可能になります。
domain=vox.com の CometBiscuit で、ログアウトするときにこのクッキーが消去されます。このクッキーはログインクッキーと違ってすべてのユーザのページに送信されるので、このクッキーがあるかないかでVOXはユーザがログインしているかどうかをチェックしているようです。これがない場合は userid.vox.com のクッキーがあったとしても無条件でログインしていないとみなすしくみになっているようです。
どうなっているのだろう、と、実際にSCRIPTタグを入れてみたらすぐにわかりました。
VOXは投稿された内容のうち、SCRIPTタグで囲まれた部分をHTMLの中にそのまま表示せず、そのかわりに別のドメイン a*.vox-data.com にSCRIPTが書かれているだけのHTMLを用意してそのHTMLをIFRAMEで表示するようになっていました。
こうするとユーザのページとスクリプトが読み込まれるページのドメインが異なるのでスクリプトからクッキーを読み出すことはできない状態のままで、任意のスクリプトを実行可能にすることができます。
ページの中身を参照して何かを出力したりするブログパーツは機能しませんし、スクリプトが埋め込まれているURLを参照するようなものも機能しなくなりそうですが、そういったことをしないスクリプトを含めて全く入れられないところからは一歩前進することができます。
VOXは、ユーザのページと管理ページと両方に送られる読み取られても問題のないクッキーを利用してログインしているかどうかだけを調べ、ユーザのページで再度そのユーザのページだけで有効な認証用のクッキーを発行するためのインターフェイスを用意することで、ログイン状態を表示できるようにしていました。しかし、この方法ではクッキーを盗まれたときの被害を小さくすることができますが、盗まれることを防止することはできません。
VOXはSCRIPTタグの内容を別ファイルにして、異なるドメインに置いたHTMLから読み込み、そのHTMLをIFRAMEでページに埋め込むことで任意のスクリプトを安全に実行できるようにしていました。このアプローチですべてのスクリプトが機能するわけではありませんが、正しく機能するスクリプトもあるでしょうから、セキュリティと利便性の落としどころのひとつとして知っていて損はなさそうです。
トラックバック元エントリにこのエントリへのリンクがない場合はトラックバックを受け付けません。
http://labs.gmo.jp/mt/mt-tb.cgi/125
comments
ご苦労様です。すごいわかりやすい!
なるほど~