CORSとは何か?
CORS(Cross-Origin Resource Sharing、オリジン間リソース共有)は、Webブラウザにおけるセキュリティ機能の一つで、異なるオリジン(ドメイン、プロトコル、ポートの組み合わせ)間でのリソース共有を制限します。Webアプリケーションが別のドメインのAPIやリソースにアクセスしようとすると、CORSポリシーによってブロックされることがあります。
CORSエラーが発生する状況
以下のような状況でCORSエラーが発生します:
- Webサイト(例:
https://example.com)のJavaScriptから別ドメインのAPI(例:https://api.another-domain.com)へ直接アクセスしようとした場合 - 対象のAPIサーバーが適切なCORS関連のレスポンスヘッダーを返さない場合
ブラウザのコンソールには以下のようなエラーメッセージが表示されます:
Access to fetch at 'https://api.another-domain.com/data' from origin 'https://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
プロキシを使用したCORSエラーの回避方法
CORSエラーを回避する最も一般的な方法の一つは、同一オリジン上のプロキシスクリプトを経由することです。
動作原理
- クライアントサイド(JavaScript)は外部APIに直接アクセスする代わりに、同じドメイン上にあるプロキシスクリプトにリクエストを送信
- サーバーサイドのプロキシスクリプトが外部APIにリクエストを転送
- プロキシスクリプトは外部APIからのレスポンスを受け取り、それをクライアントに返す
この方法では、ブラウザは同一オリジンのリソースにのみアクセスするため、CORSポリシーに違反しません。

PHP実装例
プロキシスクリプト(proxy.php)
<?php
// CORSヘッダーを設定
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); // すべてのオリジンからのアクセスを許可
header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); // 許可するHTTPメソッド
header('Access-Control-Allow-Headers: Content-Type, Authorization'); // 許可するヘッダー
// リクエストパラメータを取得
$api_url = isset($_GET['url']) ? $_GET['url'] : '';
$method = isset($_GET['method']) ? strtoupper($_GET['method']) : 'GET';
// APIのURLが指定されていない場合はエラー
if (empty($api_url)) {
http_response_code(400);
echo json_encode(['error' => 'API URL is required']);
exit;
}
// cURLセッションを初期化
$ch = curl_init();
// リクエストメソッドに応じた設定
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
// POSTデータがある場合はそれを設定
if (isset($_POST) && !empty($_POST)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST));
} else {
// JSON形式のリクエストボディがある場合
$json_body = file_get_contents('php://input');
if (!empty($json_body)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_body);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
}
}
} elseif ($method === 'GET' && isset($_GET) && !empty($_GET)) {
// GETパラメータを転送(url以外のパラメータ)
$params = $_GET;
unset($params['url']);
unset($params['method']);
if (!empty($params)) {
$api_url .= (strpos($api_url, '?') === false) ? '?' : '&';
$api_url .= http_build_query($params);
}
}
// cURLオプションを設定
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 本番環境では true に設定すべき
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; ProxyScript/1.0)');
// リクエストを実行
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
// エラーチェック
if (curl_errno($ch)) {
http_response_code(500);
echo json_encode(['error' => 'Curl error: ' . curl_error($ch)]);
curl_close($ch);
exit;
}
// レスポンスヘッダーを設定
http_response_code($http_code);
if ($content_type) {
header('Content-Type: ' . $content_type);
}
// レスポンスを返す
echo $response;
// cURLセッションを閉じる
curl_close($ch);
?>
クライアントサイドJavaScriptでの使用例
// 外部APIに直接アクセスする代わりに、プロキシを経由
fetch('./proxy.php?url=https://api.example.com/data&method=GET')
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch(error => {
console.error('Error:', error);
});
// POSTリクエストの例
fetch('./proxy.php?url=https://api.example.com/create&method=POST', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'Example', value: 123 }),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch(error => {
console.error('Error:', error);
});
jQueryでの実装例
$.ajax({
url: './proxy.php',
method: 'GET',
data: {
url: 'https://api.example.com/data',
method: 'GET',
// その他のAPIパラメータ
param1: 'value1',
param2: 'value2'
},
success: function(data) {
console.log('データ取得成功:', data);
},
error: function(xhr, status, error) {
console.error('エラー:', error);
}
});
プロキシスクリプトのセキュリティ対策
プロキシスクリプトは便利ですが、セキュリティリスクも伴います。以下の対策を検討してください:
- アクセス先URLの制限:
- 信頼できるドメインのみにアクセスを許可
- ホワイトリストによるドメイン制限を実装
// 許可するドメインのリスト
$allowed_domains = ['api.trusted-domain.com', 'data.example.org'];
// URLからドメインを抽出
$url_parts = parse_url($api_url);
$domain = isset($url_parts['host']) ? $url_parts['host'] : '';
// ドメインがホワイトリストにあるか確認
if (!in_array($domain, $allowed_domains)) {
http_response_code(403);
echo json_encode(['error' => 'Domain not allowed']);
exit;
}
- レート制限の実装:
- 短時間に多数のリクエストを送信する攻撃を防ぐ
- セッションやIPアドレスごとにリクエスト回数を制限
- リクエストの検証:
- 不正なパラメータやインジェクション攻撃を防ぐ
- 入力値のバリデーションを徹底する
本番環境での考慮事項
- SSL証明書の検証を有効に:
- 本番環境では
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);に設定 - 適切なCAバンドルを指定
- 本番環境では
- 適切なエラーハンドリング:
- 詳細なエラーメッセージは開発環境でのみ表示
- 本番環境ではエラーの詳細を隠蔽
- ログ記録:
- 異常なアクセスパターンを検出するために適切なログを記録
- 個人情報やセンシティブデータはログに記録しない
まとめ
プロキシスクリプトを使用することで、フロントエンドのJavaScriptからCORSポリシーを気にせずに外部APIにアクセスできるようになります。ただし、セキュリティリスクも考慮し、適切な対策を講じることが重要です。
この方法は特に以下のケースで有効です:
- 外部APIがCORSヘッダーを提供していない場合
- APIキーなどの機密情報をクライアントサイドに公開したくない場合
- リクエストを集約して管理・監視したい場合
プロキシスクリプトは実装が比較的簡単で、多くのWeb開発環境で利用できる便利なソリューションです。
WEBプログム、WEBデザインなどの制作については、以下を御覧ください。
WEBプログム、WEBデザインなどの制作