JavaScript プログラミング講座

 

クロスオリジンリソースシェアリングについて

 


■クロスオリジンリソースシェアリング(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 メソッドの種類を指定する

 
Access-Control-Allow-Methods ヘッダを使用します。
 
安全ではないメソッドが、コントロールの対象となります。(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);
 

■認証情報を含むリクエストの許可を設定する

 
Access-Control-Allow-Credentials ヘッダを使用します。
 
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