JavaScript を用いて クロスドメイン で リクエストを行いたいと思うと、 "同一制限元ポリシー(Same Origin Policy)" に引っかかります。 そもそもその制約にある背景は何か…といったところから、制約内容、制約の例外、制約の回避についてまとめました。
制約する理由
クロスサイトリクエストフォージェリ(CSRF)対策。 悪意あるサイトからの不正な要求を拒否するため。
制約の回避方法を見ていてもそうですが、信頼できるサーバーかのリクエストしか受け付けないようになっているようです。
制約の内容 ― 同一生成元ポリシー(Same Origin Policy)
以下の3条件がすべて満たされている場合のみ、XMLHttpRequest によるデータ送信 & 受信が行えます。 それ以外は基本的に通信が拒否されます。
- スキーム(http / https)が同じ
- ホスト(サーバー名、IPアドレス)が同じ
- ポートが同じ
ちなみに パス はどのように変わっても通信できます。
制約の例外 ― 制約されないリソース
以下のリストに挙げる リソース の取得は クロスドメイン制約 を受けません。
script タグ
による JavaScript リソース の取得。link タグ
による CSS リソース の取得。@font-face
による webフォント の取得。img タグ
による 画像ファイル の取得。video タグ
,audio タグ
による マルチメディアファイル の取得。object タグ
,embed タグ
,applet タグ
による プラグイン。frame タグ
,iframe タグ
による 別サイトコンテンツ の取得。
制約の回避 ― Cross-Origin Resource Sharing (CORS)
CORS 仕様 を満たすことで、クロスドメインリクエストを利用できるようになります。 考えるべきは次の 2 + 1 パターンです。
- GET リクエスト(プリフライト 不要)
- GET 以外の リクエスト(POST, PUT、DELETE 等)(プリフライト 必要)
- Cookie 操作 (withCredentials 指定)
(※正確には POST の一部で プリフライト 不要 ですが、特性的に "私は" プリフライトを行った方が良いと考えるので上記のように記載します。)
次のような状況を想定して、具体的にどのようなヘッダーを設定してやりとりするかを以下にまとめます。
GET リクエスト (プリフライト無し)
GET は特に制約なく簡単に回避できます。
- サーバーA から クライアント へ WEBコンテンツ を取得
- クライアント から サーバーB へのリクエストで追加するヘッダー
GET
- Origin: http://servera
- サーバーB から クライアント へのレスポンスで追加するヘッダー
- Access-Control-Allow-Origin: *
POST, PUT, DELETE リクエスト (プリフライト有り)
実通信を始める前に、OPTION で サーバーB と通信を行って許可される通信元であることを確認します。 (=プリフライト) GET 以外 の場合、プリフライトが必要になります。
- サーバーA から クライアント へ WEBコンテンツ を取得
- クライアント から サーバーB へのリクエスで追加するトヘッダー
OPTIONS
- Origin: http://servera
- Access-Control-Request-Method: POST
- Access-Control-Request-Headers: X-PINGOTHER
- サーバーBからクライアントへのレスポンスで追加するヘッダー
- Access-Control-Allow-Origin: http://servera
- Access-Control-Allow-Methods: POST, GET, OPTIONS
- Access-Control-Allow-Headers: X-PINGOTHER
- Access-Control-Max-Age: 1728000
- クライアント から サーバーB へのリクエストで追加するヘッダー
POST
,PUT
,DELETE
等
- Origin: http://servera
- サーバーB から クライアント へのレスポンスで追加するヘッダー
- Access-Control-Allow-Origin: http://servera
withCredentials 指定
Cookie 操作を行う場合、レスポンスヘッダーに Access-Control-Allow-Credentials
が必要になります。
また、 withCredengials 指定する場合、Access-Control-Allow-Origin: *
(ワイルドカード指定)が使えません。
必ずホスト名(サーバー名 または IPアドレス)を指定します。
以下の例では GET メソッド の場合を例に示します。
- サーバーA から クライアント へ WEBコンテンツ を取得
- クライアント から サーバーB へのリクエストで追加するヘッダー
- Origin: http://servera
- サーバーB から クライアント へのレスポンスで追加するヘッダー
- Access-Control-Allow-Origin: http://servera
- Access-Control-Allow-Credentials: true
参考記事
- IBM - URL の構成要素
- IT用語辞典 - スキームとは【 scheme 】
- IT用語辞典 - プロトコルとは 【 protocol 】
- 同一生成元ポリシー
- HTTP access control (CORS)
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!