«前の日記(2007-12-06 (木)) 最新 次の日記(2007-12-08 (土))»  

まちゅダイアリー


2007-12-07 (金)

クロスドメインのセキュリティ問題を OAuth で解決する

ちゃんと検証してない思いつきレベルの話。

JSONP や Flash の crossdomain.xml を使ったクロスドメインアクセスで機密情報を取得する場合は、(何も対策をしないと)機密情報が外部に漏洩するという問題があるけど、この対策に OAuth が使えるんじゃないかと思った。

クロスドメインの制約

何だか前にも書いた気がするけど、思い出せないのでもう一度書く。

いわゆる Ajax (XMLHTTPRequest やその他の方法) を使えば、ある画面を表示しながらバックグラウンドで他の情報を取得することができる。 なるべく画面遷移をせずに処理を進めるのに便利なので、最近では良く使われるようになっている。 ただ、どのデータでも自由に取得できるかというとそうではなくて、たいていは「クロスドメインの制約」ってのがある。

例を挙げると、「はてなブックマーク」の画面を表示しているとき(Webブラウザのアドレスバーが http://d.hatena.ne.jp/ のとき)は、はてなブックマーク上のデータは動的に取得できる。 「GMail」の画面を表示しているとき(アドレスバーが http://mail.google.com/ のとき)は、 GMail 上のデータを動的に取得できる。 でも、「はてなブックマーク」の画面を表示しているときに、動的に GMail のデータは取得できないようになっている。 もし取得できちゃうと、はてなブックマークの管理者が悪意のあるスクリプトを仕掛けることで、利用者の GMail の内容を読むことができるようになってしまうから。

これがクロスドメインの制約。

で、抜け道として JSONP のデータを <script src> で取得したり、 crossdomain.xml を設定して Flash でデータを取得したりって方法がある。

クロスドメインのセキュリティ

ドメインを超えてデータにアクセスできると便利なことがたくさんある。 WebAPIを公開して、JavaScript経由でアクセスできるようにするとかね。 でも、もともと禁止されていることを可能にしているのだから、何も考えないと当然問題になる。

データが公開情報(Google Mapsの地図とか)であれば、クロスドメインでアクセスされても特に困らない。 でも、機密情報(個人のメールとか連絡先とか)の場合は、無条件にクロスドメインでアクセスされると困る。 さっきのはてなブックマークとGMailの例のようにね。

だから、クロスドメインで機密情報を公開するときは、ちゃんと対策を考えないといけない。 以下参考。

クロスドメインでのアクセスに OAuth トークンを使う

この問題の本質は、「意図しないサイトに機密情報が公開されてしまう」ってことだと理解している。 なので、対策として「許可したサイトにだけ機密情報を公開するようなアクセス制御の仕組みを用意」すればいい。 例えば、 Flash の crossdomain.xml はアクセスを許可するサイトを明記できるようになってる*1

ただ、この方法だと動的にポリシーを切り替えることが難しい。例えば、ユーザごとに許可するドメインを変えるということができない(…よね?動的にcrossdomain.xmlを出力すればできる?)。 WebAPI を使うシーンでの「機密情報」ってのは、「利用者の個人的な情報」な訳だから、どのサイトに公開するかはユーザが決められるべき。 サイトの管理者が公開先をいちいち crossdomain.xml に書くような仕組みだとスケールしない。

んで、「許可したサイトにだけ機密情報を公開するようなアクセス制御の仕組み」ってとこで、WebAPI のアクセス制御に使える OAuth という仕様という話を思い出したという訳。

OAuth で登場するのは、次の三者になる。

  • Provider … OAuth API の提供者。 WebAPI でユーザの機密情報を公開する。 Twitter や Flickr などが該当。
  • Consumer … OAuth API の利用者。 JSONP などで公開されているユーザの機密情報をユーザの許可を得て取得する。
  • ユーザ

普通の OAuth の使い方だとこうなる。

  1. Consumer が Provider に WebAPI を利用するためのトークンを要求する
  2. Consumer へのトークンの発行をユーザが許可する。
  3. Provider が Consumer へトークンを発行する
  4. Consumer が WebAPI 経由で Provider 上のユーザの機密情報を取得する(発行されたトークンを一緒に送る)

ユーザの JavaScript 経由で WebAPI を使うときにも、同じように OAuth のトークンを付けてあげればいい。 OAuth のトークンを付けられるのはユーザが許可した Consumer だけ。他のサイトは OAuth トークンを知らないので、ユーザの機密情報を取得できないって訳。

デメリットは WebAPI を呼び出すたびに OAuth トークンへ署名をつけなきゃいけないことかな。 署名を付けるための鍵は Consumer が持っているので、

  • ユーザは Consumer にトークンと署名を要求する
  • Consumer は鍵を使ってトークンに署名を付与する
  • ユーザは WebAPI 経由で Provider 上の機密情報を取得する(トークンと署名を一緒に送る)

という手間が必要になる。

まとめ

OAuth を使えば、クロスドメインで機密情報を公開するときのセキュリティ対策になるかもって話だった。 図を描かなかったので、分かりにくかったかも。

それから、クロスドメイン問題にはそれほど詳しくないので、間違いがあったら指摘をお願いします。

*1 そのうち XMLHTTPRequest も同じような仕組みを採用するのかな、よく知らない

OAuth のアイデアに kazuho さんからツッコミをいただいた

[あとで]タグがついた id:kazuhooku さんのブクマにスターを付けたら、エントリでツッコミをいただいた。

なんとなく書いてくれると嬉しいなという軽い気持ちだったのですが、催促したみたいで申し訳ないです。

OAuth が使えるということはサーバサイドでマッシュアップが可能だということであり、そのような状況下において、あえてクライアントサイドでマッシュアップを行うメリットがあるのか (ユーザーに公開非公開の決定権を与えたいのであれば、任意のサイトと OAuth を可能にすればいいだけ)。

データを組み合わせるのであればサーバサイドでいろいろな演算を行いたいだろうと思うし、そこをあえて、可能性が限定されるクライアントサイドで行う必然性があるユーセージモデルが自分には見えません。

OAuth が使えるならサーバ同士で直接データをやり取りすればいいのに、わざわざクライアント側でやる必要あるの?というツッコミだと理解しました。 僕もそれほどちゃんと考えていなかったので、この機会に考えてみました。

  • 負荷軽減 … Consumer 側に負荷をかけたくない場合。 Consumer が Provider 側に接続するためのオーバーヘッドを User に代行させる。
  • Provider が提供する WebAPI の制限 … Google Search API が JavaScript だけの提供になったように、 WebAPI として JavaScript のみを提供する場合

例えば、 GMail のような Web メールのサービス提供者が、アドレス帳を JavaScript の WebAPI として提供するような場合を考えました。 SNS のサービス提供者が OAuth の Consumer になって、 SNS の招待状を送りたい相手をアドレス帳から選んでもらう。 ここまでは JavaScript で実行して、選択後のアドレスだけを Consumer に送るような場合だと、クライアント側のマッシュアップもありえるのかなと思いました。 まぁ、 OAuth の Signature を生成するのは Consumer なので、負荷軽減の効果は少し微妙ですが。

※ SNS とアドレス帳の関係は yaari.comからの招待状を無視してください (recompile.net)に書かれていることをちょっとヒントにしました。

それ OpenAuth で (ry

クライアント側でマッシュアップしたいケースについて、 id:kazuhooku さんから再びツッコミをいただいた。

AOL OpenAuth のように、iframe でメールアドレスを選択させて、その結果を親フレームに返すようにすべきだと思いました

なるほど。 クライアント側でのマッシュアップで Service Provider → Consumer の流れなら IFRAME + HTTP Referfer を使った方が軽いということですね。 OpenAuth の仕組みは全然追っていなかったので、 id:shinichitomita さんのエントリをもう一度読んで勉強します。まず、そこから把握しないと議論にもならなそうですね。

OAuth のような権限委譲の仕組みを用いる意味が大きいのは、いちいちユーザーの許可を求めずに Consumer がデータソースにアクセスすべき場合だと思います

Consumer がデータソースにアクセスする例としては、(当たり前ですが) Twitter のアーカイブサービスや、 moo が Flickr の写真にアクセスする場合ですね。 「ユーザの許可を求めず」ってことがポイントというのは、考えてもいませんでした。

Google Search API が JavaScript のみの提供となったのは、サードパーティのウェブサービスが Google Search の成果を蓄積して再利用するのを防ぎたいという理由からだと思いますが、「ユーザーのデータ」についてそのような囲い込みを行うというのは、考えにくいように思いました

僕はユーザのデータも Google Search と同様に今後は囲い込まれるものと思っています。 ただ JavaScript の API だから囲い込めるかどうかは、よく分かっていません。 ここはたぶん、議論しても解がでないところでしょうね。 ユースケースはもう少し考えてみます。

そのような技術が検討され、公開されるのであれば、それはいいことだと思います

ありがとうございます。 僕にとっても、このような議論ができることはとても有益です。 考えを深めるいいキッカケになっています。