Same-Origin PolicyとCORSの設定について
1. CORSのエラーについて
Ajaxなどのリクエストで、「CORSポリシーによってブロックされています」というエラーを見ることがあります。
CORSエラーの例
Access to XMLHttpRequest at 'http://localhost/restful/public/api/memo/1' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Failed to load resource: net::ERR_FAILED
2. Same-Origin Policyとは
ブラウザは、クロスサイトリクエストフォージェリ (CSRF) などの攻撃を防ぐため、「同一生成元ポリシー (Same-Origin Policy)」という仕組みを実装しています。これは、異なるオリジンのリソースへのアクセスに制約をかけるものです。
オリジンとは
オリジン (Origin) は、スキーム、ホスト、ポート番号の組み合わせです。
例: http://www.example.com:80
であれば、スキームが http
、ホストが www.example.com
、ポート番号が 80
の3つを合わせてオリジンとなります。
http://www.example.com:80 の場合)
異なるオリジンとみなされる例 (-
https://www.example.com/
(スキームが異なる) -
http://dev.example.com/
(ホストが異なる) -
http://www.example.com:8080/
(ポート番号が異なる)
http://www.example.com:80 の場合)
同じオリジンとみなされる例 (http://www.example.com/
http://www.example.com:80/
http://www.example.com/index.html
Same-Origin Policyの要約
ざっくり言うと、異なるWebサイトからのリクエストは制限される (シンプルリクエストを除く) ということです。
3. CORSとは
CORS (Cross-Origin Resource Sharing) とは、Cross-Origin Resource Sharingの略で、「オリジン間リソース共有」を意味します。Same-Origin Policyで送信できないものをホワイトリストで許可する設定です。
4. CORSの設定方法
エラーログに示されているように、「Access-Control-Allow-Origin」ヘッダーが存在しないことが原因です。CORSを設定するには、このヘッダーを送信すればよいです。
Apacheでの設定例
-
すべて許可する場合:
Header set Access-Control-Allow-Origin "*"
-
特定の1オリジンを許可する場合 (例: http://www.example.jp):
Header set Access-Control-Allow-Origin "http://www.example.jp"
Access-Control-Allow-Originの注意点
- オリジンは1つ、または「*」による全許可しか選べません。
- 複数ヘッダーを追加する方法は、試したところできませんでした。
複数のオリジンを許可したい場合 (動的なヘッダー生成)
ApacheのHeader設定だけでは複数のオリジンを許可できないため、「アクセス元のオリジンを動的に入れる」ことで複数オリジンに対応できます。PHPなどでアクセス元のオリジンを動的にヘッダーに入れる方法があります。
PHPでの設定例
<?php
$reqHeaders = apache_request_headers();
$allowedOrigin = array(
'https://www.example.jp',
'https://127.0.0.1',
'null', // 'null' も許可リストに入れることがある
);
if ($reqHeaders && isset($reqHeaders['Origin'])) {
if (in_array($reqHeaders['Origin'], $allowedOrigin)) {
header("Access-Control-Allow-Origin: {$reqHeaders['Origin']}");
}
}
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: x-requested-with, Content-Type, authorization, accept, client-security-token, token, x-locale, origin, x-xsrf-token');
header('Access-Control-Expose-Headers: Content-Security-Policy, Location');
header('Access-Control-Allow-Credentials: true');
?>
他にもApacheでmod_rewriteを使う方法もあります。
5. CORSでAjaxを許可する場合の追加設定
CORSでAjaxを許可する場合、プリフライトリクエストへの対応が必要です。Access-Control-Allow-Origin
だけでなく、以下のヘッダーも必要となります。
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
6. Cookieを送信する場合のSameSite属性
Cookieを送信するにはSameSite属性も必要です。
「同じeTLD + 1を持つWebサイトは、『同じサイト (same-site)』と見なされます。異なるeTLD + 1を持つWebサイトは、『クロスサイト』です」。
例: https://www.example.com:443
と https://sub.example.com:443
はeTLD+1が同じため、same-siteとなります。
名前 | 効果 | 詳細 |
---|---|---|
Strict | SameSiteでのみCookie送信 | セキュリティが強く、Chromeでは未指定だとこれになります。 |
Lax | 特定の条件下でのみCookie送信 (クロスサイトの場合、HTTPメソッドがGETなど) | セキュリティは中程度です。 |
None | クロスサイト、同一サイト関係なく送信する | Secure属性が必須で、セキュリティは弱いです。 |
AjaxでCookieを送信する場合の追加設定
-
Access-Control-Allow-Credentials: true
を付ける (ApacheまたはPHP側) -
Access-Control-Allow-Origin
を*
以外にする - JavaScript側 (Ajax, Fetch API) で
withCredentials
をtrue
(クレデンシャルモード) にする
7. Same Origin Policyで制限されるもの
- JavaScriptでの非同期通信(Ajax, いわゆる XMLHttpRequest や Fetch API を使った通信)
- CSSでの
@font-face
を使ったWebフォントの読み込み - WebGLテクスチャの読み込み
- canvasの
drawImage()
を用いた画像やビデオフレームの描画 - 画像からCSSシェイプの生成
8. Same Origin Policyで制限されないもの (シンプルリクエスト)
-
<img>
タグのsrc
属性で読み込んだ画像 -
<link>
タグのhref
属性で読み込んだCSS -
<script>
タグのsrc
属性で読み込んだJavaScript -
<form>
タグのaction
属性で設定した送信先URL -
<video>
,<audio>
タグのsrc
属性で読み込んだマルチメディアファイル -
<iframe>
,<frame>
タグのsrc
属性での別サイトコンテンツの読み込み (※X-Frame-Optionsの設定によっては読み込みがブロックされます。JavaScriptを用いてiframe内のドキュメントにアクセスすることはできません)
9. CURLなどブラウザ以外の場合
Same Origin Policyはブラウザのセキュリティなので、CURLなどは対象外です。CURLではリクエストが投げられ、レスポンスも返ってきます。
10. LaravelでのCORS設定
Laravel 7.0以降では、config/cors.php
にCORSが設定できます。ワイルドカードや正規表現によるオリジンの指定が可能です。
11. CORB (Cross-Origin Read Blocking)
CORB (Cross-Origin Read Blocking) は、ある種の攻撃を防ぐために、画像デコーダやJavaScriptエンジンがクロスオリジンのリソースを読み込む前にブロックする仕組みです。
まとめ
- 異なるWEBサイトからのリクエストを制限するSame Origin Policyというものがあります。
- CORS (
Access-Control-Allow-Origin
) でアクセス許可ができます。 -
Access-Control-Allow-Origin
は通常1オリジンのみですが、頑張れば複数オリジンも対応可能です。
Discussion