CORSの仕組みを図で解説:クロスオリジン通信を理解しよう
ウェブ開発において、セキュリティは常に最重要課題の一つです。その中でも、クロスオリジン・リソース共有 (CORS) は、ウェブアプリケーションが異なるオリジン間で安全にリソースを共有するための重要なセキュリティメカニズムです。しかし、CORSの仕組みは複雑で、完全に理解するにはある程度の学習が必要です。
この記事では、CORSの仕組みをわかりやすい図解を交えながら、徹底的に解説します。CORSの基本的な概念から、具体的な動作、設定方法、そしてセキュリティ上の考慮事項まで、網羅的にカバーすることで、読者の皆様がCORSを完全に理解し、安全なウェブアプリケーションを開発できるようになることを目指します。
1. オリジンとは何か?:CORSの基本概念
CORSを理解する上で、まず「オリジン (Origin)」という概念を理解する必要があります。オリジンとは、ウェブページがどこから来たのかを特定するための情報であり、以下の3つの要素で構成されます。
- プロトコル (Protocol):
http
やhttps
など、データの転送に使用する通信プロトコル。 - ホスト名 (Hostname):
example.com
やwww.example.com
など、ウェブサイトをホストするサーバーのドメイン名。 - ポート番号 (Port Number): サーバーがリクエストをリッスンするポート。通常、
http
はポート80、https
はポート443を使用するため、省略されることが多い。
例えば、https://www.example.com:8080/path/to/resource.html
というURLの場合、オリジンは https://www.example.com:8080
となります。
同じオリジン (Same-Origin) とは、この3つの要素がすべて一致する状態を指します。一方、異なるオリジン (Cross-Origin) とは、これらの要素のいずれかが異なる状態を指します。
図1: オリジンの構成要素
+-----------------------------------+
| URL |
+-----------------------------------+
| https://www.example.com:8080/path/to/resource.html |
+-----------------------------------+
| プロトコル | ホスト名 | ポート番号 | パス |
+-----------------------------------+
| https | www.example.com | 8080 | /path/to/resource.html |
+-----------------------------------+
| オリジン |
+-----------------------------------+
| https://www.example.com:8080 |
+-----------------------------------+
2. Same-Origin Policy (同一オリジンポリシー) とは?
ブラウザには、Same-Origin Policy (同一オリジンポリシー) という重要なセキュリティ機能が組み込まれています。これは、あるオリジンで実行されているスクリプトが、異なるオリジンからのリソースにアクセスすることを制限するものです。
このポリシーが存在する理由は、悪意のあるウェブサイトが、ユーザーがログインしている他のウェブサイト (例えば、銀行のウェブサイト) のデータを盗むことを防ぐためです。もしSame-Origin Policyがなければ、悪意のあるウェブサイトは、銀行のウェブサイトに偽のAPIリクエストを送信し、ユーザーの口座情報などを取得することが可能になってしまいます。
図2: Same-Origin Policyの動作
+-----------------------------------+ +-----------------------------------+
| www.example.com (オリジンA) | | api.example.com (オリジンB) |
+-----------------------------------+ +-----------------------------------+
| スクリプトを実行中 | | APIエンドポイント |
| XMLHttpRequest (XHR) でオリジンBにリクエスト | | リソースを提供する |
| Same-Origin Policy によってチェックされる | | |
+-----------------------------------+ +-----------------------------------+
| 同じオリジンならアクセス許可 | | |
| 異なるオリジンならアクセス拒否 | | |
+-----------------------------------+ +-----------------------------------+
3. CORSの登場:クロスオリジン通信の必要性
Same-Origin Policyはセキュリティ上非常に重要ですが、完全に制限してしまうと、異なるオリジン間でリソースを共有する必要がある正当なユースケースも存在します。例えば、
- API連携: フロントエンドアプリケーションが、異なるドメインでホストされているAPIサーバーからデータを取得する必要がある場合。
- CDN: コンテンツデリバリーネットワーク (CDN) から画像やスクリプトなどの静的アセットを配信する場合。
- マイクロサービスアーキテクチャ: 複数の独立したマイクロサービスが異なるドメインでホストされ、互いに連携する必要がある場合。
これらのユースケースに対応するために、CORS (Cross-Origin Resource Sharing) が導入されました。CORSは、Same-Origin Policyの制約を緩和し、特定のオリジンからのリクエストを許可するためのメカニズムを提供します。
4. CORSの仕組み:プリフライトリクエストと単純リクエスト
CORSは、ブラウザとサーバーの間で特別なHTTPヘッダーをやり取りすることで機能します。CORSには、主に以下の2つのタイプのリクエストがあります。
- プリフライトリクエスト (Preflight Request): リクエストが「複雑」な場合に、実際のHTTPリクエストを送信する前に、ブラウザがサーバーに送信する事前確認のリクエストです。
- 単純リクエスト (Simple Request): 特定の条件を満たすリクエストは、プリフライトリクエストなしで直接送信されます。
4.1. プリフライトリクエスト
プリフライトリクエストは、OPTIONS
メソッドを使用して送信されます。このリクエストには、以下のヘッダーが含まれます。
Origin
: リクエストを発行したオリジン。Access-Control-Request-Method
: 実際のHTTPリクエストで使用するメソッド (例:GET
,POST
,PUT
,DELETE
)。Access-Control-Request-Headers
: 実際のHTTPリクエストで使用するカスタムヘッダーのリスト。
サーバーは、プリフライトリクエストを受け取ると、Access-Control-Allow-Origin
ヘッダー、Access-Control-Allow-Methods
ヘッダー、Access-Control-Allow-Headers
ヘッダーを含むレスポンスを返します。
Access-Control-Allow-Origin
: リソースへのアクセスを許可するオリジン。*
を指定すると、すべてのオリジンからのアクセスを許可します。Access-Control-Allow-Methods
: 許可するHTTPメソッドのリスト (例:GET, POST, PUT
)。Access-Control-Allow-Headers
: 許可するカスタムヘッダーのリスト。Access-Control-Max-Age
: プリフライトリクエストの結果をキャッシュする時間 (秒単位)。
ブラウザは、サーバーからのレスポンスを検証し、Access-Control-Allow-Origin
ヘッダーにリクエストを発行したオリジンが含まれているか、または *
が指定されているかを確認します。また、Access-Control-Allow-Methods
ヘッダーと Access-Control-Allow-Headers
ヘッダーに、実際のHTTPリクエストで使用するメソッドとヘッダーが含まれているかを確認します。
検証に成功した場合、ブラウザは実際のHTTPリクエストをサーバーに送信します。検証に失敗した場合、ブラウザはリクエストをブロックし、コンソールにエラーメッセージを表示します。
図3: プリフライトリクエストのフロー
+-----------------------+ +-----------------------+
| ブラウザ | | サーバー |
+-----------------------+ +-----------------------+
| 1. プリフライトリクエスト (OPTIONS) | --> | 2. OPTIONSリクエストを受信 |
| Origin: www.example.com | | |
| Access-Control-Request-Method: POST | | |
| Access-Control-Request-Headers: Content-Type | | |
+-----------------------+ +-----------------------+
| | <-- | 3. レスポンス (CORSヘッダー付き) |
| | | Access-Control-Allow-Origin: www.example.com |
| | | Access-Control-Allow-Methods: POST, GET |
| | | Access-Control-Allow-Headers: Content-Type |
+-----------------------+ +-----------------------+
| 4. CORSチェック (OK) | | |
+-----------------------+ +-----------------------+
| 5. 実際のHTTPリクエスト (POST) | --> | 6. POSTリクエストを受信 |
+-----------------------+ +-----------------------+
| | <-- | 7. レスポンス (データ) |
+-----------------------+ +-----------------------+
4.2. 単純リクエスト
以下の条件をすべて満たすリクエストは、単純リクエストとみなされ、プリフライトリクエストなしで直接送信されます。
- メソッドが
GET
,HEAD
,POST
のいずれかである。 Accept
,Accept-Language
,Content-Language
,Content-Type
以外のヘッダーを設定していない。Content-Type
ヘッダーの値がapplication/x-www-form-urlencoded
,multipart/form-data
,text/plain
のいずれかである。
単純リクエストの場合、ブラウザは通常のHTTPリクエストを送信し、サーバーからのレスポンスに Access-Control-Allow-Origin
ヘッダーが含まれているかを確認します。ヘッダーが存在し、値がリクエストを発行したオリジンであるか、または *
である場合、ブラウザはレスポンスをスクリプトに公開します。そうでない場合、ブラウザはレスポンスをブロックし、コンソールにエラーメッセージを表示します。
図4: 単純リクエストのフロー
+-----------------------+ +-----------------------+
| ブラウザ | | サーバー |
+-----------------------+ +-----------------------+
| 1. HTTPリクエスト (GET) | --> | 2. GETリクエストを受信 |
| Origin: www.example.com | | |
+-----------------------+ +-----------------------+
| | <-- | 3. レスポンス (CORSヘッダー付き) |
| | | Access-Control-Allow-Origin: www.example.com |
+-----------------------+ +-----------------------+
| 4. CORSチェック (OK) | | |
+-----------------------+ +-----------------------+
5. CORSの設定方法:サーバー側の設定
CORSを有効にするには、サーバー側で適切なHTTPヘッダーを設定する必要があります。設定方法は、使用しているサーバーソフトウェアやプログラミング言語によって異なりますが、基本的な考え方は同じです。
以下は、一般的な設定例です。
5.1. Apache
.htaccess
ファイルまたはバーチャルホストの設定に、以下の行を追加します。
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
5.2. Nginx
サーバーブロックの設定に、以下の行を追加します。
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
5.3. Node.js (Express)
cors
ミドルウェアを使用すると、CORSの設定が簡単になります。
“`javascript
const express = require(‘express’);
const cors = require(‘cors’);
const app = express();
app.use(cors()); // すべてのオリジンからのアクセスを許可
// 特定のオリジンからのアクセスのみを許可
// const corsOptions = {
// origin: ‘http://www.example.com’
// };
// app.use(cors(corsOptions));
app.get(‘/api/data’, (req, res) => {
res.json({ message: ‘Hello from the API!’ });
});
app.listen(3000, () => {
console.log(‘Server is running on port 3000’);
});
“`
5.4. Python (Flask)
Flask-CORS
拡張機能を使用すると、CORSの設定が簡単になります。
“`python
from flask import Flask
from flask_cors import CORS
app = Flask(name)
CORS(app) # すべてのオリジンからのアクセスを許可
特定のオリジンからのアクセスのみを許可
CORS(app, origins=’http://www.example.com’)
@app.route(“/api/data”)
def hello():
return {“message”: “Hello from the API!”}
if name == ‘main‘:
app.run(debug=True)
“`
6. CORSのセキュリティに関する考慮事項
CORSは、異なるオリジン間でのリソース共有を安全に行うためのメカニズムですが、設定を誤るとセキュリティ上の脆弱性が発生する可能性があります。以下の点に注意してCORSを設定する必要があります。
Access-Control-Allow-Origin: *
の使用:Access-Control-Allow-Origin
ヘッダーに*
を指定すると、すべてのオリジンからのアクセスを許可することになります。これは、開発環境やテスト環境では便利ですが、本番環境では推奨されません。悪意のあるウェブサイトが、APIリクエストを偽装し、機密情報を盗むことができる可能性があるためです。本番環境では、許可するオリジンを明示的に指定するようにしましょう。Access-Control-Allow-Credentials
ヘッダー: CookieやAuthorizationヘッダーなどの認証情報をクロスオリジンリクエストで送信する場合は、Access-Control-Allow-Credentials: true
ヘッダーをサーバーのレスポンスに含める必要があります。また、Access-Control-Allow-Origin
ヘッダーに*
を指定することはできません。オリジンを明示的に指定する必要があります。- 入力検証の徹底: CORSは、あくまでもブラウザ側のセキュリティメカニズムであり、サーバー側のセキュリティ対策を代替するものではありません。サーバー側では、すべてのAPIリクエストに対して、適切な入力検証を行い、不正なリクエストから保護する必要があります。
7. CORSのトラブルシューティング
CORSに関する問題は、デバッグが難しい場合があります。以下は、一般的なCORSの問題とその解決策です。
- ブラウザコンソールにCORSエラーが表示される: ブラウザコンソールにCORSエラーが表示された場合は、まずサーバー側のCORS設定を確認してください。
Access-Control-Allow-Origin
ヘッダー、Access-Control-Allow-Methods
ヘッダー、Access-Control-Allow-Headers
ヘッダーが正しく設定されているかを確認します。 - プリフライトリクエストが送信されない: リクエストが単純リクエストの条件を満たしているかどうかを確認します。カスタムヘッダーを使用している場合や、
Content-Type
ヘッダーの値が正しくない場合は、プリフライトリクエストが必要になります。 Access-Control-Allow-Credentials
ヘッダーが設定されているのに、Cookieが送信されない:Access-Control-Allow-Origin
ヘッダーに*
が指定されていないかを確認します。Cookieを送信する場合は、オリジンを明示的に指定する必要があります。また、クライアント側のJavaScriptでwithCredentials = true
を設定する必要があります。
8. まとめ
この記事では、CORSの仕組みについて、図解を交えながら詳しく解説しました。CORSは、ウェブアプリケーションが異なるオリジン間で安全にリソースを共有するための重要なセキュリティメカニズムであり、ウェブ開発者にとって不可欠な知識です。CORSを理解することで、より安全で柔軟なウェブアプリケーションを開発できるようになります。
CORSの設定は、最初は複雑に感じるかもしれませんが、この記事で解説した内容を参考に、一つずつ理解していくことで、必ずマスターできるはずです。
9. 今後の学習
- MDN Web Docs: Cross-Origin Resource Sharing (CORS): CORSに関する詳細な情報が掲載されています。 https://developer.mozilla.org/ja/docs/Web/HTTP/CORS
- CORSのベストプラクティス: CORSを安全に設定するためのベストプラクティスについて学ぶことができます。
- CORSに関するセキュリティ脆弱性: CORSの設定ミスによって発生するセキュリティ脆弱性について理解を深めることができます。
CORSは、常に進化している技術です。最新の情報を常に把握し、安全なウェブアプリケーション開発を心がけましょう。