CORSリクエストヘッダーの基本を解説!Originヘッダーの仕組みと使い方
新人
「先輩、Javaの開発で別のドメインにAPIリクエストを送ろうとしたら、CORSエラーって出たんですけど、CORSってなんですか?」
先輩
「それはCORS(Cross-Origin Resource Sharing)っていうセキュリティ機能が原因だね。Webブラウザが、異なるオリジン間でのリソース共有を制限してるんだ。」
新人
「オリジンって、何を指してるんですか?」
先輩
「オリジンは、スキーム(http/https)・ドメイン・ポート番号の組み合わせを指すんだよ。たとえば、http://localhost:8080からhttp://api.example.comにアクセスするのはクロスオリジンになるんだ。」
新人
「なるほど!じゃあ、CORSで使われるリクエストヘッダーには何があるんですか?」
先輩
「よし、それじゃ今回はCORSリクエストヘッダーの仕組みと、よく使われるOriginヘッダーやAccess-Control-Request-Methodについて詳しく説明するよ。」
1. CORSとは?基本のおさらい
CORS(コース:Cross-Origin Resource Sharing)とは、異なるオリジン間でのHTTPリクエストを安全に行うための仕組みです。たとえば、http://localhost:3000のフロントエンドから、http://api.example.comのバックエンドへ通信を行う場合、これは「クロスオリジン通信」と呼ばれます。
通常、ブラウザはこのようなクロスオリジン通信をブロックします。しかし、CORSを正しく設定すれば、安全な通信が可能になります。CORSの仕組みでは、リクエストヘッダーとレスポンスヘッダーを使って、どのオリジンからの通信を許可するかを制御します。
つまり、クライアントが送る「CORSリクエストヘッダー」と、サーバーが返す「CORSレスポンスヘッダー」の組み合わせによって、通信の可否が決定されるのです。
2. CORSリクエストヘッダーとは?役割と代表例
CORSのリクエスト時に、ブラウザは自動的にいくつかのHTTPヘッダーを追加します。これが「CORSリクエストヘッダー」と呼ばれるものです。これらのヘッダーによって、ブラウザはサーバーに「この通信はクロスオリジンです」と伝え、アクセスの許可を求めます。
2-1. Originヘッダー
もっとも基本的なCORSリクエストヘッダーがOriginヘッダーです。これはリクエスト元のスキーム・ドメイン・ポートを示し、サーバーに対して「このオリジンからの通信を許可してほしい」と伝える役割を持ちます。
たとえば、以下のようなHTTPリクエストが送られます。
GET /api/data HTTP/1.1
Host: api.example.com
Origin: http://localhost:3000
この例では、クライアントがhttp://localhost:3000で、サーバーはhttp://api.example.comとなっており、異なるオリジン間での通信になっています。
2-2. Access-Control-Request-Methodヘッダー
Access-Control-Request-Methodは、プリフライトリクエスト(事前確認リクエスト)で使用されるヘッダーです。これは、実際の通信を行う前に、ブラウザがサーバーに対して「このメソッドでアクセスしたいけど許可してくれる?」と問い合わせるために使います。
たとえば、以下のようなOPTIONSリクエストが送られます。
OPTIONS /api/user HTTP/1.1
Host: api.example.com
Origin: http://localhost:3000
Access-Control-Request-Method: POST
このプリフライトリクエストに対して、サーバーがCORSレスポンスヘッダーで許可すれば、本リクエスト(POSTリクエスト)が実行されます。
2-3. Access-Control-Request-Headersヘッダー
このヘッダーは、プリフライトリクエストでクライアントが使用予定のカスタムヘッダーをサーバーに通知するために使います。
たとえば、次のようなヘッダーです。
OPTIONS /api/user HTTP/1.1
Host: api.example.com
Origin: http://localhost:3000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header
このようにして、クライアントが独自のヘッダー(例:X-Custom-Header)を使う場合にも、事前にサーバーへ通知する必要があるのです。
2-4. Javaでの確認方法(@Controllerを使用)
Spring Bootを使用している場合、@Controllerを使って受け取ったCORSリクエストを確認できます。以下のように記述すれば、リクエストヘッダーをログ出力できます。
@Controller
public class CorsExampleController {
@RequestMapping("/api/data")
@ResponseBody
public String getData(HttpServletRequest request) {
String origin = request.getHeader("Origin");
System.out.println("Originヘッダーの値: " + origin);
return "CORSリクエストを受け付けました";
}
}
このようにして、Originヘッダーなどの内容を確認しながらCORS通信を理解することができます。
3. CORSレスポンスヘッダーの意味と必要性
サーバー側では、クライアントから送られたCORSリクエストヘッダーに対して、対応する「CORSレスポンスヘッダー」を返す必要があります。このレスポンスヘッダーがないと、ブラウザはセキュリティ上の理由からレスポンスをブロックしてしまいます。つまり、CORS通信を許可するには、サーバー側で明示的に許可を示すレスポンスヘッダーを設定する必要があります。
3-1. Access-Control-Allow-Originとは
Access-Control-Allow-Originは、もっとも重要なCORSレスポンスヘッダーのひとつです。このヘッダーは「どのオリジンからのリクエストを許可するか」を指定します。
たとえば、次のように設定すると、http://localhost:3000というオリジンからのアクセスだけが許可されます。
Access-Control-Allow-Origin: http://localhost:3000
すべてのオリジンを許可したい場合は、アスタリスク(*)を使うこともできます。ただし、あとで解説する認証情報(クッキーなど)を使う場合は、*は使えません。
3-2. Access-Control-Allow-Methods
Access-Control-Allow-Methodsは、クライアントが使用できるHTTPメソッド(GET、POSTなど)を指定するレスポンスヘッダーです。
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
このヘッダーが正しく設定されていないと、プリフライトリクエストでエラーになります。
3-3. Access-Control-Allow-Headers
Access-Control-Allow-Headersは、クライアントがリクエスト時に使用するカスタムヘッダーを許可するためのレスポンスヘッダーです。
Access-Control-Allow-Headers: Content-Type, X-Custom-Header
この指定がなければ、X-Custom-Headerなどのカスタムヘッダーはブロックされます。
3-4. Access-Control-Allow-Credentials
Access-Control-Allow-Credentialsは、クライアントがクッキーや認証トークンなどの「認証情報」をサーバーに送ることを許可するために使うレスポンスヘッダーです。
Access-Control-Allow-Credentials: true
このヘッダーを使う場合、Access-Control-Allow-Originに*を設定することはできません。後述するように、設定ミスの原因にもなります。
4. Spring SecurityでCORSレスポンスヘッダーを設定する方法
Spring Securityを使用している場合、CORSのレスポンスヘッダーはWebSecurityConfigurerAdapterを拡張して設定します。以下にGradle構成のSpring Bootプロジェクトにおける基本的なCORS設定の例を示します。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors() // CORSを有効にする
.and()
.csrf().disable(); // 開発環境ではCSRFを無効化
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:3000");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true); // 認証情報を許可
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
この設定では、http://localhost:3000からのリクエストを許可し、すべてのHTTPメソッドとヘッダーを許可しています。また、setAllowCredentials(true)を設定することで、認証情報の送信も可能になります。
5. よくあるCORSレスポンスの設定ミスと対策
ここでは初心者が陥りやすいCORS設定のミスと、その対処方法を解説します。
5-1. 「*」と認証情報の併用によるエラー
Access-Control-Allow-Originを*に設定しながら、Access-Control-Allow-Credentials: trueを指定してしまうケースは非常に多いですが、これは明確な仕様違反です。ブラウザはこの組み合わせを拒否し、CORSエラーになります。
対策としては、オリジンを明示的に指定するようにします。
config.addAllowedOrigin("http://localhost:3000"); // * ではなく明示的に
config.setAllowCredentials(true);
5-2. OPTIONSリクエストが拒否される
ブラウザがプリフライト(OPTIONS)リクエストを送っても、サーバーがそのリクエストに対応していない場合、CORS通信は失敗します。
Spring Bootでは、以下のようにコントローラでOPTIONSリクエストを明示的に許可しておくと安心です。
@Controller
public class CorsOptionsController {
@RequestMapping(value = "/api/**", method = RequestMethod.OPTIONS)
@ResponseBody
public ResponseEntity<?> handleOptions() {
return ResponseEntity.ok().build();
}
}
5-3. フロントエンドとの通信テストでCORSエラー
開発初期にありがちなミスとして、フロントエンド側とバックエンド側のポート番号が異なることでCORS通信になっていることに気づかず、CORS設定を忘れてしまうことがあります。
たとえば、http://localhost:3000とhttp://localhost:8080は別オリジンとして扱われるため、CORS対応が必要です。通信ができないときは、まずはオリジンの違いを確認することが大切です。
6. 実際のリクエストとレスポンスのHTTPヘッダー表示例
CORS通信の際に発生するHTTPヘッダーは、ブラウザの開発者ツールで簡単に確認できます。たとえば、Google Chromeであれば、右クリックから「検証」→「Network」タブを開き、対象のリクエストをクリックすることで「Headers」タブに詳細が表示されます。
ここでは、フロントエンドからバックエンドへPOSTリクエストを送信した場合のリクエストとレスポンスのCORS HTTPヘッダー例を紹介します。
6-1. リクエスト時のHTTPヘッダー(例)
POST /api/login HTTP/1.1
Host: api.example.com
Origin: http://localhost:3000
Content-Type: application/json
Referer: http://localhost:3000/login
このように、Originヘッダーがhttp://localhost:3000であることにより、クロスオリジン通信であると判断されます。
6-2. レスポンス時のHTTPヘッダー(例)
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Content-Type: application/json
ここで重要なのはAccess-Control-Allow-Originが明示的に指定されている点です。また、クッキーなどの認証情報を扱う場合はAccess-Control-Allow-Credentials: trueも必須になります。
7. セキュリティの観点でのベストプラクティス
CORSの設定は柔軟であるがゆえに、セキュリティリスクも伴います。特に本番環境でのCORS設定には注意が必要です。ここでは「CORS セキュリティベストプラクティス」として、よく守られるべき設定方針を紹介します。
7-1. 不要なオリジンを許可しない
Access-Control-Allow-Originに*を指定すると、すべてのオリジンからのアクセスを許可してしまうため、非常に危険です。特に機密情報や認証機能を伴うエンドポイントでは、必ず信頼できるオリジンを明示的に指定しましょう。
config.addAllowedOrigin("https://trusted.example.com");
7-2. 認証情報の扱いに注意
クッキーやセッショントークンなどの認証情報をCORS通信で扱う場合、Access-Control-Allow-Credentialsの設定が必要です。同時に、オリジンの制限もセットで行わないと、第三者による不正アクセスが可能になるリスクがあります。
セッションを使う場合は、SameSite=NoneかつSecure属性をクッキーに付与することも忘れてはいけません。
7-3. 本番環境と開発環境の設定を分離する
開発中は利便性を重視してCORSを広く許可することがありますが、本番環境では必ずオリジンを制限しましょう。Springではプロファイル(例:dev、prod)を分けてCORS設定を切り替えることができます。
@Profile("dev")
@Bean
public CorsConfigurationSource devCorsConfig() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedMethod("*");
return source;
}
8. CORSヘッダーの設定ミスが引き起こすリスクとトラブルシューティング
CORSの設定を誤ると、正しく動作しないだけでなく、セキュリティホールを作ることにもなります。ここでは「CORS トラブルシューティング」の観点でよくあるミスとその解決方法を紹介します。
8-1. 設定は正しいのにCORSエラーが出る
レスポンスに必要なヘッダーが正しく返っていないときに発生することがあります。特に、OPTIONSメソッドへの対応漏れが原因のことが多いため、@RequestMapping(method = RequestMethod.OPTIONS)があるかを確認してください。
8-2. フロントエンド側の設定不備
JavaScript側でfetchやaxiosを使う際に、credentials: 'include'を指定していないと、クッキーが送信されません。バックエンドがAccess-Control-Allow-Credentialsを返していても、クライアント側の指定がなければ意味がありません。
8-3. ブラウザのキャッシュが悪さをする
一度CORSエラーが出ると、ブラウザがキャッシュした情報のせいで、設定変更後も同じエラーが続く場合があります。念のためブラウザのキャッシュをクリアしたり、シークレットモードで再確認するとよいでしょう。
8-4. Spring Securityの順序が影響している
Spring SecurityでCORSの設定よりも先にセキュリティ制限が働いてしまうと、CORSレスポンスヘッダーが返らないケースがあります。http.cors()の順序やFilterRegistrationBeanの設定順に注意してください。
まとめ
この記事では、CORSリクエストヘッダーとレスポンスヘッダーの仕組みを中心に、CORSとは何か、Originヘッダーの役割、プリフライトリクエスト(OPTIONS)、そしてSpring Boot・Spring Securityでの具体的な設定方法までを丁寧に解説してきました。
CORSは一見すると難しく感じやすい仕組みですが、基本に立ち返ると「ブラウザが異なるオリジン間の通信を安全に管理するためのルール」であることが分かります。 特に重要なのは、クライアントが送るCORSリクエストヘッダーと、サーバーが返すCORSレスポンスヘッダーがセットで機能している点です。
Originヘッダーは「どこから来たリクエストか」を示し、Access-Control-Request-Method や Access-Control-Request-Headers は「これから何をしたいか」を事前に伝えます。 それに対してサーバー側は、Access-Control-Allow-Origin や Access-Control-Allow-Methods などを使って「どこまで許可するか」を明確に示します。 このやり取りの合意が取れなければ、ブラウザは通信をブロックします。
また、Access-Control-Allow-Credentials と Access-Control-Allow-Origin の組み合わせや、OPTIONSリクエストの扱いなど、設定ミスが起きやすいポイントも多く存在します。 CORSエラーが出たときは、コードだけを見るのではなく、「どのオリジンから」「どのヘッダーが」「どの順序で」送られているのかを落ち着いて確認することが重要です。
CORS理解を助ける確認用サンプルコード
最後に、CORSの理解を深めるためのシンプルな確認用サンプルをもう一度整理しておきましょう。 以下は、ブラウザから送られる代表的なCORSリクエストヘッダーの例です。
GET /api/data HTTP/1.1
Host: api.example.com
Origin: http://localhost:3000
このリクエストに対して、サーバーが次のようなレスポンスヘッダーを返せば、ブラウザは通信を許可します。
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
この「OriginとAllow-Originの一致関係」を確認するだけでも、多くのCORSエラーは原因が見えてきます。
生徒
「最初はCORSエラーが出るたびに、何が起きているのか全然分からなかったんですが、 Originヘッダーとレスポンスヘッダーの関係を意識すると、少しずつ見えてきました。」
先生
「それが一番大事なポイントだね。CORSは“魔法の設定”じゃなくて、 ブラウザとサーバーの間の確認ルールにすぎないんだ。」
生徒
「特に、Access-Control-Allow-Origin に * を使えばいいと思っていたのが間違いだと分かりました。 認証情報があると使えないんですね。」
先生
「そう。便利そうに見える設定ほど、実は制限があることが多い。 だからこそ、CORSは“なぜその設定が必要なのか”を理解しながら使うことが重要なんだ。」
生徒
「これからCORSエラーが出ても、慌てずにリクエストヘッダーとレスポンスヘッダーを確認してみます。」
先生
「それで大丈夫。CORSを理解できたということは、Webの仕組みを一段深く理解できた証拠だよ。」