Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】🌐 Understanding CORS (Cross-Origin Resource Sharing): A Complete Guide

2025年09月27日に「Dev.to」が公開したITニュース「🌐 Understanding CORS (Cross-Origin Resource Sharing): A Complete Guide」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

CORS(Cross-Origin Resource Sharing)は、異なるドメインのWebアプリ間でリソースを安全にやり取りするためのブラウザセキュリティ機能だ。悪意あるリクエストを防ぐため、許可された通信以外はブラウザがブロックする。開発者はHTTPヘッダーでこの仕組みを正しく設定し、フロントエンドとバックエンド間の安全な連携を確保する必要がある。

ITニュース解説

システムエンジニアを目指す初心者がウェブアプリケーション開発で必ず出会うことになるセキュリティ機能の一つに「CORS(Cross-Origin Resource Sharing)」がある。これは、ウェブブラウザが持つ非常に重要なセキュリティ機能で、異なる「オリジン」からのリソース要求をどのように扱うかを制御する役割を担っている。

オリジンとは、ウェブサイトの住所のようなもので、「プロトコル(例: http, https)」「ドメイン(例: example.com)」「ポート番号(例: 80, 443, 3000)」の3つの要素で構成される。これら3つのうち、どれか一つでも異なれば、それは「異なるオリジン」と判断される。例えば、ウェブサイトのフロントエンドがhttp://localhost:3000で動作し、バックエンドのAPIがhttp://localhost:8080で動作している場合、これらはポート番号が異なるため、ブラウザから見ると別々のオリジンと認識される。このフロントエンドがバックエンドのAPIにデータを取りに行こうとすると、それは「クロスオリジンリクエスト」となる。適切なCORSの設定が行われていないと、ブラウザはこのリクエストをセキュリティ上の理由から自動的にブロックしてしまう。

CORSの仕組みは、ブラウザとサーバー間でやり取りされるHTTPヘッダーによって機能する。リクエストには「単純なリクエスト」と「プリフライトリクエスト」の二種類がある。

まず「単純なリクエスト」は、HTTPメソッドがGET、POST、HEADのいずれかであり、かつ、ヘッダーが「安全なもの」(例えば、Accept、Content-Typeがapplication/x-www-form-urlencoded、multipart/form-data、text/plainのいずれか)のみである場合に発生する。例えば、http://example-frontend.comというオリジンを持つフロントエンドが、GETメソッドで/api/productsにリクエストを送る場合、ブラウザはそのリクエストヘッダーにOrigin: http://example-frontend.comという情報を自動的に追加してサーバーに送信する。サーバーはこれを受け取ると、応答ヘッダーにAccess-Control-Allow-Origin: http://example-frontend.comのような情報を含めて返す。このサーバーからの応答ヘッダーに含まれるオリジンが、ブラウザがリクエストを送った元のオリジンと一致すれば、ブラウザはリクエストの処理を許可する。一致しない場合は、セキュリティ上の理由でリクエストをブロックする。

次に「プリフライトリクエスト」は、単純なリクエストの条件を満たさない場合に発生する。具体的には、PUTやDELETEといったHTTPメソッドを使用する場合、あるいはAuthorizationX-Custom-Headerのようなカスタムヘッダーをリクエストに含める場合、またはContent-Typeが安全でないタイプの場合などである。このようなリクエストでは、ブラウザは実際のリクエストを送信する前に、まず「OPTIONS」メソッドを使った「プリフライトリクエスト」をサーバーに自動的に送信する。これは、「これからこのようなリクエストを送ろうと思うけれど、許可してもらえるか?」というサーバーへの事前確認のようなものだ。ブラウザはプリフライトリクエストのヘッダーにOriginAccess-Control-Request-Method(これから使うメソッド)、Access-Control-Request-Headers(これから使うヘッダー)などの情報を含めてサーバーに送る。サーバーはこれを受け取り、許可するオリジン、メソッド、ヘッダーのリストをAccess-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headersなどの応答ヘッダーとしてブラウザに返す。また、Access-Control-Max-Ageというヘッダーで、プリフライトリクエストの結果をどのくらいの期間キャッシュして再利用できるかを指定することもある。このプリフライトリクエストの応答に基づいて、ブラウザが本番のリクエストを安全に送れると判断した場合にのみ、実際のデータ送信のリクエスト(例えばPUTやDELETE)が行われる。

CORSはユーザー保護のために非常に重要である。悪意のあるウェブサイトが、あなたの認証情報を使って他のサイトへ勝手にリクエストを送るような攻撃(クロスサイトリクエストフォージェリ、CSRF)を防ぐ役割も担っている。また、ウェブアプリケーションの管理者にとっては、どのオリジンからのアクセスを許可し、どのHTTPメソッドやヘッダーを許可するかを細かく制御できるため、セキュリティと柔軟性を両立させる上で欠かせない機能となっている。現代のウェブアプリケーションで、フロントエンドとバックエンドが異なるドメインやポートで動作する場合、正しいCORS設定は必須となる。

CORSの設定ミスは、開発中によく遭遇する問題の原因となる。最も一般的なのは、「No 'Access-Control-Allow-Origin' header is present on the requested resource.」というエラーメッセージだ。これは、サーバーがフロントエンドのドメインからのアクセスを許可するように設定されていない場合に発生する。また、クッキーや認証トークンといった資格情報(credentials)をクロスオリジンリクエストで送りたい場合、サーバー側でAccess-Control-Allow-Credentials: trueというヘッダーを設定する必要がある。このとき、Access-Control-Allow-Originヘッダーに*(ワイルドカード、全てのオリジンを許可)を使用することはできない点に注意が必要だ。プリフライトリクエストが正しく処理されないと、ブラウザが本番のリクエストを送信しないため、やはりリクエストがブロックされてしまうこともある。安易にAccess-Control-Allow-Origin: *と設定することは、セキュリティリスクを高めるため避けるべきである。

実際のCORS設定は、使用するバックエンドフレームワークによって異なるが、Go言語のGinフレームワークを使った例を見てみよう。コードは省略するが、主要な設定項目としてAllowOriginsには許可するフロントエンドのURL(例: http://localhost:3000, https://myapp.com)を配列で指定する。AllowMethodsで許可するHTTPメソッド(例: GET, POST, PUT, DELETE)を、AllowHeadersで許可するリクエストヘッダー(例: Origin, Content-Type, Authorization)を指定する。AllowCredentials: trueとすることで、認証クッキーやトークンといった資格情報の送受信を許可する。MaxAgeは、プリフライトリクエストの応答をブラウザがキャッシュする期間を設定するもので、頻繁なプリフライトリクエストを減らすことでパフォーマンス向上に役立つ。このように適切に設定することで、例えばhttp://localhost:3000で動くReactのフロントエンドから、http://localhost:8080で動くGoのAPIへスムーズにリクエストを送ることができるようになる。

実世界のウェブアプリケーションでは、フロントエンドがNetlifyのようなホスティングサービス(例: https://myapp.netlify.app)にデプロイされ、バックエンドがAWS EC2などのサーバー(例: https://api.myapp.com)で動くことはよくある。このような場合でも、バックエンド側で正しいCORS設定を行っていなければ、ブラウザはフロントエンドからのAPIリクエストをブロックしてしまう。適切なCORSヘッダーが設定されていれば、これらの異なるオリジン間でスムーズなAPI通信が可能となる。

CORSを扱う上でのベストプラクティスとしては、まずAccess-Control-Allow-Origin*(ワイルドカード)を使用することは、特に機密性の高いAPIでは避けるべきである。常に許可するオリジンを具体的に指定し、開発、ステージング、本番といった環境ごとに異なるオリジンを設定することが望ましい。バックエンドでは、プリフライト(OPTIONS)リクエストを適切に処理するように設定し、Access-Control-Max-Ageを活用してプリフライトリクエストの回数を減らすことを検討しよう。また、必要のないヘッダーやメソッドを安易に許可しないことも重要である。CORSはあくまでブラウザのセキュリティ機能であり、ウェブアプリケーション全体のセキュリティをCORSだけに頼るべきではない。認証やレート制限といった他のセキュリティ対策も併用することが不可欠である。

最新のウェブ開発では、JavaScriptのfetch APIを使う際にmode: "cors"credentials: "include"といったオプションを設定することがあり、これらはバックエンドのCORS設定と整合している必要がある。また、最近ではPrivate Network Access (PNA)という新しいセキュリティ機能が導入され、http://192.168.x.xのようなプライベートネットワークへのリクエストに対して、ブラウザが追加のプリフライトリクエストを行うようになっている。開発環境でCORSの問題を一時的に回避するために、Reactのcreate-react-appのようにpackage.jsonでプロキシを設定する手法もあるが、これはあくまで開発時の回避策であり、本番環境ではバックエンドでCORSを正しく設定する必要がある。

CORSは、最初はエラーメッセージが分かりにくく、戸惑うことも多いかもしれないが、ウェブにおける最も重要なブラウザのセキュリティ機能の一つだ。フロントエンドとバックエンドが異なるオリジンで通信する現代のウェブアプリケーションを開発する上では、CORSを正しく理解し、適切に設定することが不可欠である。安易にAccess-Control-Allow-Origin: *と設定するのではなく、どのオリジン、どのヘッダー、どのメソッドを許可するのが安全かを慎重に検討し、一度設定したらその内容を文書化しておくことで、後々のデバッグ時間を大幅に削減できるだろう。

関連コンテンツ

関連IT用語