JSONPという字面を久々に見ることがあり、なついなーと思ってCORSとの違いについてまとめてみた。
JSONPとCORSの共通点
どちらもブラウザの同一生成元ポリシーによる制限を潜り抜け、クロスドメインでの通信・アクセスができるようになる仕組みである。
今ではほとんどの場合、CORSが使われる。
同一生成元ポリシー
同一生成元ポリシーは、ホスト、スキーム、ポートをひと組みとしてオリジンとすべて一致するときに同一生成元とみなす考え方のことで、オリジンと異なるコンテンツに対してセキュリティ上の干渉を阻止するための制限である。
1995年にNetscape社によってJavaScriptと同時にブラウザに導入された。
具体的には下記のような制限がある。
- XMLHttpRequest(Ajax)による取得の禁止
- スクリプトによる別のオリジンであるiframeやwindowに対する操作の制限(iframe.contentWindow、window.parent、window.open、window.openerなど)
- Canvasへの一部の操作の制限
この制限がない場合、例えばログインしないとみることのできない情報のあるサイトにログインしているとき、ほかの生成元のサイトからそれを取得されるなどの危険が生じる。
JSONP(JSON with padding)
JSONPは、scriptタグを利用してクロスドメインのデータを取得する仕組み。
同一生成元ポリシーは画像やJavaScript、CSSの埋め込みは制限されていない。
これを利用して、HTMLのscriptタグのsrc属性に別ドメインのURLを指定し、データを取得する手段がJSONPである。
例えば、phpプログラムのパスをsrc属性に設定し、任意のクエリ文字列を指定する。
phpプログラムでそのクエリ文字列を受け取り、それに応じたjsonオブジェクトを出力することで、 オリジンのJavaScriptで扱えるといった実装がよくなされる。
<!-- こんなかんじ -->
<script src="https://example.com/getjson?callback=XXX"></script>
扱う上での注意点として、CSRFの脆弱性に注意が必要である。
src属性に設定するエンドポイントは外部に公開されているため、悪意のあるサイトがデータを取得するといったことが可能であることから、機密情報や個人情報などのデータを取り扱うには不向きである。
またオリジンにおいてもリモートサイトから任意の内容のデータをページに差し込むことが可能であるため、JavaScriptインジェクションに対する脆弱性がある場合は、注意が必要である。
そのためデータを提供するサーバ側では、リクエストの正当性を検証する必要がある。
CORS(Cross-Origin Resource Sharing – オリジン間リソース共有)
追加のHTTPヘッダーを使用して、異なるオリジンにもリソースへのアクセス権を与えるようブラウザーに指示するための仕組みのこと。
具体的には別オリジンのリソースに下記のようなレスポンスヘッダーを追加する必要がある。
Access-Control-Allow-Origin: https://example.com // 特定のサイトを許可
Access-Control-Allow-Origin: * // すべてのサイトを許可
Access-Control-Allow-Headers "X-Requested-With, Origin, X-Csrftoken, Content-Type, Accept" // 許可するヘッダーの定義
GET、POST、HEADリクエストを利用する場合は、「Access-Control-Allow-Headers」を指定する必要はないが、それ以外のメソッドを利用する場合は下記のようにアクセスを許可するメソッドをレスポンスヘッダーに含める必要がある。
Access-Control-Allow-Methods: PUT, DELETE, PATCH
オリジン側の注意点としては、JavaScriptのFetch APIを使用する場合「cors mode」の設定を行う必要がある。
またCookieも含めてリクエストを送りたいという場合、デフォルトでは異なるオリジンに対してCookieは送信されず、Fetch APIやXMLHttpRequestなどにオプションを付与する必要がある(別オリジンも「Access-Control-Allow-Origin: *」としている場合は動作しないため、特定のサイトを記述する必要がある)。