APIサーバでCORSを使う
昨日はSODECに行ってきました。
最近はこうした展示会でこれはスゲー!という衝撃をうけることは少ないんですが、プロダクトを見る時に「どういう風に作ってるんだろうなぁ」ということを想像しながら眺めているせいか、ちょいちょい今まで考えもしなかったようなことを思いつきます。(毎回そうなんですが思いつく内容が特定のプロダクトからの直接の連想でないところが不思議なところです。ほとんどの場合帰り道や寝る直前などにふと降りてきます。(^^;)
今回の話はその思いつきの内容のメモです。
あ、あと知人の吉田さんに著書をいただきました。
帰りに1章だけ読みましたが、自分(開発者)とは違う視点からセキュリティを俯瞰している印象でなかなか興味深いです。
技術者だけでなく経営層の人も読んでみると良いかも。(ステマ)
★ CORSとは
Cross Orign Resource Sharingの略でその名の通り異なるドメインでリソースを共有するための仕組みです。
JavaScriptにはSame Origin Policyがあるので通常は異なるドメインのREST APIをAjaxでたたくことはできませんが、CORSを使うとそれが可能になります。
資料としてはこれがわかりやすいです。
https://developer.mozilla.org/ja/docs/HTTP_access_control
一番有名な実装例はおそらくAmazon S3で、CORSを利用することでブラウザからのファイルのS3への直接アップロードを可能にしています。
★ CORSのサーバサイド実装
上記リンク先を見ると実装に必要なことはだいたいわかるんですが、大まかにまとめると以下のようになります。
- HttpResponseのAccess-Control-Allow-Originでアクセスを許可するOriginを指定する
- 同じくAccess-Control-Allow-Methodsで許可するメソッドを指定する
- プリフライトリクエストに備えてHTTPメソッドのOPTIONSに対応する
- Cookieを使用する場合はAccess-Control-Allow-Credentials: true をつける
ほとんどHttpヘッダの制御だけなのでたいていのフレームワークではハンドル可能です。唯一OPTIONSへの対応だけが不安でしたが、とりあえずPlayframeworkではroutesに普通に「OPTIONS /hogehoge ...」を定義するだけでいけました。
クライアント側はブラウザがよしなにやってくれるので基本的には自分で実装すべきものはありません。(というかHttpClient自体を自前で用意するのであればそもそもSameOriginPolicyの制限を受けないので何もする必要がありません。)
唯一Cookieを利用する場合は自分でxhr#withCredentialsをtrueにする必要があります。jQueryだとやり方にすこし癖がありますがこの辺を見ればすぐにできると思います。
★CORSをAPIサーバで使うことを考える
さて、このCORS。僕はS3の事例でしか使ったことがなかったので静的に設定するモノという先入観があったんですが、よくよく考えるとHttpヘッダだけの対応なので動的に変更することが可能です。
例えばユーザ毎に固有のURLを用意するようなサービスの場合、URL毎にAccess-Control-Allow-Originを変更することは楽勝でできますし、認証後にすべてのユーザに対して同一のURLでAPIを提供するようなサービスであってもCookie併用で切り替えることができるはずです。
これで指定のドメイン以外からのリクエストをはじくことができますが、curlやChromeのコンソールなどからでも簡単に偽装リクエストを送ることはできるのでセキュリティ要件は別途考えなければなりません。
あとは、ブラウザからの直接アクセスをはじくためにOriginヘッダのないリクエストははじくなどの対応を入れても良いでしょう。
これらができると、今まではSameOriginPolicy回避のためにサーバから実行するしかなかった外部APIの実行がブラウザ上から直接できるようになるので、アプリの可能性は大きく広がりそうな気がします。
★ 既存サービスの実装状況など
自分に思いつく程度のことだから既存のサービスではもう結構実装されてるんじゃないの?とおもってざっと検索してみましたが、あんまりそういうサービスない(追記)みたいですね。
Salesforceで検索してみたら3年も前によく見知った人が対応しろや!と声をあげていて流石と思いましたが、未だ対応されていないようです。残念。。。
その中で異彩をはなっているのは我らがHerokuです。
https://devcenter.heroku.com/articles/platform-api-reference#cors
え、「*」で許可してるってこと???
それは流石にやりすぎなんじゃ。。。(--
つーことは、つまりHeroku DashboardはGitHub.ioでも作れるってことですね。(^^;
(追記)
文中のよく見知った人(冨田さん)から、Google+ API, Facebook Graph API, GitHub APIがCORSに対応していることを教えていただきました。ありがとうございます。
これらも「*」で許可しているみたいですね。先行して認証があるAPIの場合はそれもアリな選択肢ということなんでしょう。
コメント