クロスオリジンリソースシェアリングについて
■クロスオリジンリソースシェアリング(CORS)について
Cross-Origin Resource Sharing(CORS)は、HTML5 世代の仕様です。
W3Cにより、仕様が勧告されています。
http://www.w3.org/TR/cors/
■生成元(オリジン)について
生成元(オリジン)とは、自身のリソースが格納されている場所です。
「プロトコル、ドメイン、ポート番号」の3つを合わせたものです。
■同一生成元ポリシー (Same-Origin Policy) による制限
任意の Web ページから、別オリジン下に格納されている一部のリソースを、読み取りアクセスする事はできません。
例えば、XMLHttpRequest は、受信に失敗します。
例えば、Web フォントは、ダウンロードに失敗します。
■リソースシェアリングを許可するには?
サーバー側にて、アクセスコントロール情報を、付加する事ができます。
この設定を行うと、別のオリジン下のコンテンツから、自身のサーバのリソースが読み取りアクセスされる事を許します。
リソースシェアリングを許可するには、Access-Control-Allow-Origin ヘッダを使用します。
■サーバー側のセキュリティについて
クロスオリジンリソースシェアリングは、アクセスの遮断はできません。
ブラウザが自主的にデータを受信しないだけであり、ソケット接続などからアクセスを試みるとデータの受信は可能です。
よって、公開する機密情報の取り扱いに注意します。
■静的なアクセスコントロールの設定
■ .htaccess ファイルを使用する
「http://sub.example.com:8080」からのみ、リソースシェアリングを許す
Header append Access-Control-Allow-Origin: "http://sub.example.com:8080"
「http://aaa.com」と「http://bbb.com」からのみ、リソースシェアリングを許す
Header append Access-Control-Allow-Origin: "http://aaa.com http://bbb.com"
すべてのサイトから、リソースシェアリングを許す
Header append Access-Control-Allow-Origin: "*"
■動的なアクセスコントロールの設定
■CGI から、レスポンスヘッダを出力する
プリフライトリクエストに対応する場合、CGI が必要です。
CGI を使って、動的にレスポンスヘッダを出力します。
クライアントからは、Origin ヘッダなどの、リクエスト情報が送られてきます。
すべてのサイトから、リソースシェアリングを許す (Perl)
#!/usr/local/bin/perl
print "Access-Control-Allow-Origin: *\n";
print "Content-type: text/plain\n";
print "\n";
print "Hallo World!!";
すべてのサイトから、リソースシェアリングを許す (PHP)
<?php
header("Access-Control-Allow-Origin: *");
header("Content-type: text/plain");
echo "Hallo World!!";
?>
すべてのサイトから、リソースシェアリングを許す (Ruby)
#!/usr/local/bin/ruby
print "Access-Control-Allow-Origin: *\n"
print "Content-type: text/plain\n"
print "\n"
print "Hallo World!!"
すべてのサイトから、リソースシェアリングを許す (Python)
#!/usr/local/bin/python
# coding: utf-8
# ライブラリをロード
import sys
# Content-type を出力
sys.stdout.write("Access-Control-Allow-Origin: *\n")
sys.stdout.write("Content-type: text/plain\n")
sys.stdout.write("\n")
sys.stdout.write("Hallo World!!")
アクセスコントロールについて
■アクセスコントロールの種類について
■レスポンスヘッダ(サーバー側)
ヘッダフィールド名 | 説明 | 必須 |
Access-Control-Allow-Origin | 許可するオリジンを設定する | ○ |
Access-Control-Allow-Methods | 許可する HTTP メソッドの種類を設定する | |
Access-Control-Allow-Headers | 許可するリクエストヘッダの種類を設定する | |
Access-Control-Allow-Credentials | 認証情報を含むリクエストの許可を設定する | |
Access-Control-Max-Age | プリフライトの有効時間を指定する(単位:秒) | |
Access-Control-Expose-Headers | 要求するリクエストヘッダの種類を、オープンに公開する |
■リクエストヘッダ(クライアント側)
ヘッダフィールド名 | 説明 |
Origin | リクエスト側のオリジン情報を、サーバ側に通知する (自動) |
Access-Control-Request-Method | メインの HTTP メソッドの種類を、サーバ側に通知する (自動) |
Access-Control-Request-Headers | 改変したリクエストヘッダの種類を、サーバ側に通知する (自動) |
■許可するクライアント側の生成元(オリジン)を指定する
Access-Control-Allow-Origin ヘッダを使用します。
指定したオリジンのコンテンツから、リソースをシェアされる事を許可します。
それ以外は、全て拒絶します。
複数のオリジンを指定したい場合、空白で区切ります。
すべてのオリジンを許可したい場合、『 * 』を指定します。
「http://sub.example.com:8080」のみ、リソースシェアリングを許す
Access-Control-Allow-Origin: "http://sub.example.com:8080"
「http://aaa.com」と「http://bbb.com」のみ、リソースシェアリングを許す
Access-Control-Allow-Origin: "http://aaa.com http://bbb.com"
すべてのサイトから、リソースシェアリングを許す
Access-Control-Allow-Origin: *
■許可する HTTP メソッドの種類を指定する
安全ではないメソッドが、コントロールの対象となります。(PUT, DELETE など)
単純なメソッドは、常に許可されます。(GET, POST, HEAD, OPTIONS など)
複数の HTTP メソッドを指定したい場合、『 , 』で区切ります。
■ヘッダ例(サーバ側)
PUT メソッドを許可する
Access-Control-Allow-Methods: PUT
PUT と DELETE と PATCH メソッドを許可する
Access-Control-Allow-Methods: PUT, DELETE, PATCH
■プリフライトリクエストについて(クライアント側)
安全ではない HTTP メソッドを指定し、さらにクロスオリジン通信となる場合、プリフライトリクエストが発生します。
まず OPTIONS メソッドで通信を行い、次に、通常の XHR 通信が発生するようになります。
■許可するリクエストヘッダの種類を指定する
Access-Control-Allow-Headers ヘッダを使用します。
この設定は、プリフライト用です。
OPTIONS メソッドで通信した場合のみ影響があります。
それ以外のメソッドで通信した場合、設定に関係なくすべて許可されます。
■ OPTIONS メソッドで通信した場合
リクエストヘッダ内に、指定したヘッダ情報が含まれない場合、拒絶します。
複数のリクエストヘッダを指定したい場合、『 , 』で区切ります。
複数指定した場合、1つでも抜けがあると拒絶します。
■ヘッダ例(サーバ側)
「X-Unknown」ヘッダが含まれる場合のみ許可する(OPTIONS メソッド通信時のみ)
Access-Control-Allow-Headers: "X-Unknown"
「X-Unknown-0」と「X-Unknown-1」ヘッダが両方含まれる場合のみ許可する(OPTIONS メソッド通信時のみ)
Access-Control-Allow-Headers: "X-Unknown-0, X-Unknown-1"
■プリフライトリクエストについて(クライアント側)
リクエストヘッダ情報を改変し、さらにクロスオリジン通信となる場合、プリフライトリクエストが発生します。
まず OPTIONS メソッドで通信を行い、次に、通常の XHR 通信が発生するようになります。
リクエストヘッダにカスタム情報を追加する
// ------------------------------------------------------------
// XMLHttpRequest オブジェクトを作成
// ------------------------------------------------------------
var xhr = new XMLHttpRequest();
// ------------------------------------------------------------
// XHR 通信が成功したときに実行されるイベント
// ------------------------------------------------------------
xhr.onload = function(e){
// 出力テスト
console.log(e);
};
// ------------------------------------------------------------
// 「GET メソッド」「接続先 URL」を指定
// ------------------------------------------------------------
xhr.open("GET" , "http://example.com/test.cgi");
// ------------------------------------------------------------
// リクエストヘッダにカスタム情報を追加する
// ------------------------------------------------------------
xhr.setRequestHeader("X-Unknown-0" , "Hello");
xhr.setRequestHeader("X-Unknown-1" , "World");
// ------------------------------------------------------------
// XHR 通信を開始する
// ------------------------------------------------------------
xhr.send(null);
■認証情報を含むリクエストの許可を設定する
true か false を指定します。
クロスオリジン通信かつ、認証情報を含む場合のみ、影響があります。
同じオリジンからの通信は、設定に関係なくすべて許可されます。
認証情報を含まない場合は、設定に関係なくすべて許可されます。
■ false を指定した場合
異なるオリジンからの認証リクエストは、すべて拒絶します。
デフォルトは、false です。(省略時)
■ true を指定した場合
信頼しないオリジンからの認証リクエストは、拒絶します。
信頼するオリジンからの認証リクエストは、許可します。
■信頼するオリジンを設定する
Access-Control-Allow-Origin ヘッダを使用します。
この場合、指定できるオリジンは、1つのみです。
* 指定はできません。
■信頼するオリジンを複数指定するには?
CGI などを使って、動的にレスポンスヘッダを出力します。
クライアントから送られてきた、Origin ヘッダの値を確認します。
信頼できる場合、そのまま出力します。
■ヘッダ例(サーバ側)
信頼するオリジンから、認証情報を含むリクエストが送られてきた場合、許可する
Access-Control-Allow-Origin: "http://sub.example.com:8080"
Access-Control-Allow-Credentials: true
異なるオリジンから、認証情報を含むリクエストが送られてきた場合、すべて拒絶する
Access-Control-Allow-Credentials: false
■クライアント側の実装について
こちらで解説しています。
■クライアントから認証情報を送信する(クロスオリジン通信時)
■ XHR 送信のデフォルトの動作について
同じオリジンに送信する場合、認証情報は常に含まれます。
異なるオリジンに送信する場合、認証情報は含まれません。
認証情報が含まれるように、制限を解除する事もできます。
■ XHR 送信時に認証情報を含める
XMLHttpReqest クラスの、withCredentials プロパティを使用します。
true を指定した場合、Cookie などの認証情報を送信するようになります。
デフォルトは、false です。
この設定は、クロスオリジン通信時にのみ作用します。
同じオリジンに送信する場合、認証情報は常に含まれます。
■サーバー側の実装について
Access-Control-Allow-Credentials ヘッダに、true を指定します。
■送信例
異なるオリジンに対しても、Cookie などの認証情報を送信する(HTML5 世代)
// ------------------------------------------------------------
// XMLHttpRequest オブジェクトを作成
// ------------------------------------------------------------
var xhr = new XMLHttpRequest();
// ------------------------------------------------------------
// XHR 通信が成功したときに実行されるイベント
// ------------------------------------------------------------
xhr.onload = function(e){
// 出力テスト
console.log(e);
};
// ------------------------------------------------------------
// 「GET メソッド」「接続先 URL」を指定
// ------------------------------------------------------------
xhr.open("GET" , "http://example.com/test.cgi");
// ------------------------------------------------------------
// Cookie などの認証情報を送信する
// ------------------------------------------------------------
xhr.withCredentials = true;
// ------------------------------------------------------------
// XHR 通信を開始する
// ------------------------------------------------------------
xhr.send(null);
■プリフライトの有効時間を指定する
Access-Control-Max-Age ヘッダを使用します。
指定する数値の単位は、秒です。
指定時間内の場合、プリフライトリクエスト処理が、発生しなくなります。
以下のレスポンスヘッダ情報が、キャッシュされます。
ヘッダフィールド名 | 説明 |
Access-Control-Allow-Methods | 許可する HTTP メソッドの種類を設定する |
Access-Control-Allow-Headers | 許可するリクエストヘッダの種類を設定する |
■ヘッダ例(サーバ側)
プリフライトの有効時間を 300 秒とする
Access-Control-Max-Age: 300