2018-01-06

SOP(Same Origin Policy)とCORS(Cross Origin Resource Sharing)について調べた

SOP(Same Origin Policy)の理解が怪しいなぁと思ったのでちゃんとした仕様を調べた。
同時にCORS(Cross Origin Resource Sharing)についても調べることになったのでまとめて整理した。

SOP(Same Origin Policy: 同一生成元ポリシー)

  • Webブラウザなどのセキュリティ機能の1つ
  • ある オリジン から読み込まれた文書やスクリプトについて、そのリソースから他の オリジン のリソースにアクセスできないように制限するもの

※ 参考:https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy

オリジンとは

スキーム、ポート、ホストがそれぞれ等しいものが、同じオリジンと見なされる http://domain-a.com/dir/page.html をベースとした場合、次のようになる。

(o) http://domain-a.com/dir2/other.html
(o) http://domain-a.com/dir/inner/another.html
(x) https://domain-a.com/secure.html
-> スキームが異なる
(x) http://domain-a.com:81/dir/etc.html
-> ポートが異なる
(x) http://domain-b.com/dir/other.html
-> ホストが異なる

※ 補足

  • IPアドレスは見ていない
  • パスが異なるだけのものは問題ない

※ 参考:https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy#Definition_of_an_origin

制限されるもの

  • XMLHTTPRequestによる取得
  • スクリプトによる別のオリジンであるiframewindowに対する操作
  • Canvasへの一部の操作

制限されないもの

SOP(同一生成元ポリシー)には許されているものがいくつかある。 以下、異なるオリジンに埋め込むことができるリソースの例。

  • <script src="..."></script> によるJavaScript
  • <link rel="stylesheet" href="..."> によるCSS
  • <img>による画像
  • <video>, <audio>によるメディアファイル
  • <object>, <embed>, <applet> によるプラグイン
  • @font-face で指定されたフォント
  • <frame>, <iframe>に関連する様々なもの
  • <form>からの送信

異なるオリジンへのアクセスを許可する方法

  • かつてはJSONPという手法が使われていた(JSONPについては省略)
  • 現在では CORS を使用することが推奨されているようだ

CORS (Cross Origin Resource Sharing)

  • SOPはセキュリティ上重要な仕組みだが、まっとうなWebアプリケーション開発者にとってはオリジンをまたいだアクセスが必要になるケースが多かった。そこでCORSが登場した
  • Webサーバがドメインをまたぐアクセスを制御する方法を規定することで、ドメイン間の安全な通信を保証する
  • つまり、CORSの仕様に則れば、ドメインをまたいだアクセス(クロスオリジンHTTPリクエスト)ができるようになる

※ 参考:https://developer.mozilla.org/ja/docs/Web/HTTP/HTTP_access_control#Overview

CORSのパターン

大きく2つのパターンがある

  • (1) simple cross-origin request
  • (2) actual request(プリフライトがある)

simple cross-origin requestになる条件は以下の通り

  • HTTPメソッドがGET,POST,HEADのいずれかである
  • HeaderがAccept,Accept-Language, Content-Language, Content-Type以外を含まない
  • Content-Typeを含む場合、その値がapplication/x-www-form-urlencoded, multipart/form-data, text-plainのいずれかである

上記の条件に合致しない場合はactual requestというプリフライトが必要なパターンになる

※ 参考:『Real World HTTP』10章

プリフライトリクエストとは

  • 実際の通信の前に、権限確認目的で送信するリクエストのこと
  • プリフライトリクエストはHTTPメソッドのOPTIONSを使って送信される
  • リクエストには以下のヘッダを含む
    • Access-Control-Request-Method: 通信を許可してもらいたいメソッド
    • Access-Control-Request-Headers: 許可して欲しいヘッダー(カンマ区切り)
    • Origin: 通信元のウェブページのドメイン名
  • プリフライトリクエストは、リクエスト前に毎回送信されるわけではない。通信内容を一定期間キャッシュすることができる。キャッシュ期間を制御するには以下のヘッダを使う
    • Access-Control-Max-Age

※ 参考:『Real World HTTP』10章