CORS 対応時の注意点などメモ


同じオリジンのAPIと非同期で通信、という場合は xhr で普通にこなしてますが、別ドメインのAPIと非同期で、となると割とつまづくポイントがあったのでメモ。

こちらのサイトが大変分りやすかったです。

+ CORSではまったこと http://inside.pixiv.net/entry/2014/12/16/181804

# xhr2 を使う

特に何かしなくても、ブラウザがxhr2対応しているものであればxhr2を使うことになります。
逆にいうと、xhr2 対応していないブラウザだとダメ。


# とりあえず普通に実装する

特にクロスドメインであることを気にかけず、クライアントサイド、サーバサイドそれぞれをまずは実装します。

# Origin 許可する

サーバサイドでアクセス元となるOriginを意識して設定する必要があります。

+ サーバサイドのレスポンスヘッダの追加
+ クライアントサイドはモダンブラウザなら特別な対応は不要

## サーバサイドの対応

Access-Control-Allow-Origin レスポンスヘッダを追加します。
セットする値は許可するアクセス元Originになります。(プロトコル + サブドメイン + ドメイン)
どこからアクセスされてもOKな場合は "*" になります。

クライアント側の環境によってはうまく処理されないケースがあるので、Access-Control-Allow-Headers レポンスヘッダも一緒に追加します。
セットする値はクライアントサイドの実装環境によって、Content-Type の外にも　X-Requested-With や　Accept や Origin などをセットしたほうがいい時があるみたいです。

以下はHTTP/SSL での foo.unknown.jp と bar.unknown.com という Origin からのアクセスだけを許可する場合の apache 側の設定例です。

```apache
SetEnvIf Origin "^https?://(foo¥.unknown¥.jp|bar¥.unknown¥.com)$" ORIGIN=$0
Header append Access-Control-Allow-Origin %{ORIGIN}e env=ORIGIN
Header append Access-Control-Allow-Headers "Content-Type"
```

**Access-Control-Allow-Origin のホワイトリスト対応の件**

上の例のような、特定複数のOriginだけ許可したい、という場合に例えばサーバ側から

```
# 注意: これはうまくいかない
Access-Control-Allow-Origin: "http://foo.unknown.jp http://bar.unknown.com"
```

となるように返しても、 **Access-Control-Allow-Origin ヘッダは１つしか値を受け付けないという内容のエラーメッセージが表示** されます。

複数許可したい、でも "*" にするわけにはいかないという場合、サーバ側でオンデマンドに許可するOriginを変更することで回避できます。

## クライアントサイド

とくに意識せずxhrリクエストを投げます。以下は jQuery での例。

```js:jQuery
$.ajax({
	url: 'https://foo.unknown.jp/api/test.json',
	type: 'get',
	dataType: 'json',
	
	success: function(result, textStatus, xhr) {
		call_back_function.call(self, result, textStatus, xhr);
	},
	error: function(xhr, textStatus, error) {
		call_back_error_function.call(self, xhr, textStatus, error);
	}
});
```

# Cookie 使う場合は更に Credentials を有効にする

Cookie をやり取りしたい場合は、Credentials を有効にする必要があります。

+ サーバサイドのレスポンスヘッダの追加
+ クライアントサイドからのリクエストで credential を有効にする

## サーバサイドの対応

Access-Control-Allow-Credentials レスポンスヘッダを追加します。
値は true にします。

```apache
Header append Access-Control-Allow-Credentials true
```

※ Access-Control-Allow-Origin が "*" になっていると使えないようです。


## クライアントサイドの対応

リクエスト時にCredentialを付けて送る必要があります。
以下はjQueryでの設定例で、xhrFields プロパティを設定しています。

```js:jQuery
$.ajax({
	url: 'https://foo.unknown.jp/api/test.json',
	type: 'get',
	dataType: 'json',
	xhrFields: {
		withCredentials: true
	},
	
	success: function(result, textStatus, xhr) {
		call_back_function.call(self, result, textStatus, xhr);
	},
	error: function(xhr, textStatus, error) {
		call_back_error_function.call(self, xhr, textStatus, error);
	}
});
```


Chrome とFirefoxはここまでの設定で大体動くようになりました。
IEはまだもう少し対応が必要です。

# IE 対応するなら利用ライブラリのバージョンを確認

IE9以前はXMLHttpRequest対応していない独自オブジェクトXDomainRequestを使うため、jQueryなどライブラリを使用している場合は使用バージョンでどう対応しているのか確認します。
ここがサポートブラウザに影響してくるかもしれません。

# IE でCookie使うなら P3P コンパクトポリシー

IEのセキュリティレベルの設定で、「すべてのCookieを受け付ける」以外にしている場合は、
P3Pコンパクトポリシーの付いているサイトでないとCookieを送信しないようです。

Cookieを発行しているリソースプロバイダが Set-Cookie レスポンスヘッダを返す時に、一緒に P3P ヘッダへコンパクトポリシーをセットして返すようにすれば、セキュリティを最低レベルにする必要がなくなります。

```
# Cookieの発行サーバで以下をレスポンスヘッダにつける
P3P: CP="NON CUR OUR NOR ONL UNI"
```

**P3Pコンパクトポリシーの設定値**

P3Pコンパクトポリシーが設定してあれば、設定値は何でも動いてしまうようです。

とはいえ[P3P](http://www.iajapan.org/trans2japanese/w3c/rec-p3p-20020416j.html)の仕様を参考にCookie発行サイトがどのようなポリシーなのか、３文字で表すトークンを組み合わせて作ってみると良いと思います。

そんなに難しいことはないですし、間違えてしまっても動きますし。


# IE のセキュリティ設定

P3Pコンパクトポリシーに対応している外部サイトの場合には、ユーザがブラウザの設定を変更することなく CORS が使えました。

P3Pコンパクトポリシーが付いていない外部サイトにCORSする場合は、以下のセキュリティ設定の変更をすれば使えるようになりました。実用することはほぼないと思いますが何かの時の参考までに。

+ インターネットオプション -- セキュリティ設定 -- インターネットゾーンのセキュリティレベルの[レベルのカスタマイズ] -- その他 -- ドメイン間でのデータソースのアクセス を有効にする
+ インターネットオプション -- プライバシー設定 -- レベルを一番低い「すべてのCookieを受け入れる」にする


# このメモを書いたときの手元の環境

参考までに。

**サーバサイド**

+ apache 2.2.27 / 2.4.12

**クライアントサイド**

+ jQuery 2.1.3
+ Chrome 41.0.2272.76
+ Firefox 36.0.1
+ IE 11.0.9600


# 参考サイト

+ CORSではまったこと http://inside.pixiv.net/entry/2014/12/16/181804
+ jQuery Documentation http://api.jquery.com/jQuery.ajax/
+ Access-Control-Allow-Origin - Mozilla Developer Network https://developer.mozilla.org/ja/docs/HTTP_access_control
+ W3C P3P 1.0 仕様書 http://www.iajapan.org/trans2japanese/w3c/rec-p3p-20020416j.html
+ IBM P3P ヘッダー内のデフォルト・コンパクト・ポリシー http://www-01.ibm.com/support/knowledgecenter/SSPREK_6.1.0/com.ibm.itame.doc_6.1/am61_webseal_admin168.htm?lang=ja
+ apache 設定ファイル内での変数フォーマット http://httpd.apache.org/docs/2.2/mod/mod_log_config.html#formats