先日CORS(Cross-Origin Resource Sharing)でハマったので、今更だけど復習。Same Origin Policy(同一オリジンポリシー)について基本的なところから調べ直しました。

オリジンとは

オリジン = スキーム、ホスト、ポートの組み合わせ
(※スキームによって微妙に違うこともある)

http://www.exsample.com:80/index.htmlのURLを例にすると

  • スキーム = http://
  • ホスト = www.exsample.com
  • ポート = 80 (ポート番号「80」は省略可なので普段見かけることは少ない)

同一オリジンポリシーとは

今北産業

  • セキュリティを守るための重要な仕組み
  • あるページを開いたときに、関連するリソース(JavaScript等)を同じオリジンからしか取得しない
  • そうしないと個人情報の保護も外部からの攻撃にもガバガバ

同一オリジンポリシーの制限を受けるWebAPI

  • XMLHttpRequest
  • Canvas
  • Web Storage
  • X-Frame-Options

制限を受けないもの

  • <script src="..."></script> によって読み込まれるJavaScript
  • <link rel="stylesheet" href="..."> によって読み込まれるCSS
  • <img>, <audio>, <video> のメディアファイル
  • @font-face で指定されたフォント
  • <frame>, <iframe>
  • <object>, <embad>, <applet>によるプラグイン

参考:異なるオリジンへのネットワークアクセス

CORSとは

別オリジンのリソースへアクセス(= クロスサイトHTTPリクエスト)できるようにするためのルール、手法。

簡単な例

ブラウザがオリジンA(http://origin-a.com)のWEBサイトを表示中に、オリジンB(http://origin-b.com)のリソースへアクセスする場合のやりとりの例です。

  • ブラウザ「オリジンA(http://origin-a.com)がおたくのリソース欲しいって」
  • オリジンB「オリジンA(http://origin-a.com)からきたの?それなら良いよ😘」

こんな会話が、ブラウザから送られるHTTPリクエストヘッダとサーバから返されるHTTPレスポンスヘッダにて行われています。

HTTPリクエストヘッダ

GET /api HTTP/1.1
Origin: http://origin-a.com

HTTPレスポンスヘッダ

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://origin-a.com

もう少し深い話

CORSの仕組みの根底はHTTPヘッダによるやりとりなのだけれど、実はこれを実現する手段は2つあります。

  1. 👆の例のように、直接クロスオリジンなリクエストを投げる
  2. 一度CORSが可能かを確認するリクエストを投げ、そのレスポンスを受けてから再度クロスオリジンなリクエストを投げる

基本的には一度CORSが可能かを確認するリクエスト(=preflightリクエスト)を投げることが必要とされていますが、以下の条件全てを満たす場合はシンプルなリクエストでもOKです。

  • HTTPメソッドがGET, POST, HEADのいずれか
  • HTTPヘッダにAccept, Accept-Language, Content-Language, Content-Type以外のフィールドが含まれない
  • Content-Typeの値はapplication/x-www-form-urlencoded, multipart/form-data, text/plainのいずれか

今回触れない話

CORSについてはもっともっと深い話があります。たとえばCORSはデフォルトではCookieを使わないのでそれを使えるようにする方法とか、リクエストに独自のリクエストヘッダを使う方法とか、IE対応の話とか…。 そのへんは今回は割愛する代わりに、参考サイトを残しておきます。