CORSの誤解を解く：読み取り防御としての本質と限界を整理してみた

# CORSとは何か？ 仕組みと対策をざっくり整理してみた


CORSって単語はよく聞くけど、調べるたびにモヤモヤして、根っこから理解できていない感じがずっとありました。
今回改めて整理してみたらスッと腹落ちしたので、自分なりにまとめておきます。同じように「名前は知ってるけど納得できてない」方の助けになれば嬉しいです。

## ✅ 対象読者とこの記事のスタンス

この投稿は、以下のような方を対象にしています：

- フロントエンド or フルスタック初学者で「CORSってよく聞くけど、結局なんなの？」と思っている方
- 開発中に「CORSエラー出た！」と焦った経験があり、背景から理解したい方
- APIを設計・実装していて、CORS対応をざっくり整理しておきたい方

**この記事で紹介すること：**

- CORSの基本的な仕組みと目的
- エラーの発生理由とその回避方法
- プリフライトリクエストの意味と発生条件
- 「CORSが防げること・防げないこと」の切り分け

**この記事では扱わないこと：**

- 各フレームワーク（Express, Railsなど）での実装方法詳細
- CDNやAPI GatewayによるCORS設定の実践例
- セキュリティの全体像（CSRFや認証認可全体）は必要に応じて触れる程度


## 🔰 CORSとは？

CORS（Cross-Origin Resource Sharing）とは、**リクエスト送信元のオリジン**（たとえば `window.location.origin` で取得できるもの）と、**リクエスト送信先**（例：`fetch("https://example.com/api/items")`）の**オリジンが異なる場合に、ブラウザが制限をかける仕組み**です。

ポイントは次の通り：

- **レスポンスを JavaScript から読めるか** を制御するものであり、**リクエスト自体を止めるものではない**
- あくまで**ブラウザの機能**なので、`curl` などのCLIツールには関係ない
- 自作ブラウザなどでCORSの仕組みを無視すれば、そもそもこの制限も回避できてしまう（だからこそ「ブラウザレベルの制約」）


## 🔒 誰から何を守っているの？

CORSは、主に「**ユーザーの認証情報を使ったクロスオリジンの読み取り系攻撃**」を防ぐためのものです。

たとえば以下のような攻撃が想定されます：

```js
fetch("https://example.com/api/getBankAccountInfo", {
  credentials: "include"
})
  .then(res => res.json())
  .then(data => steal(data)); // 攻撃者のサーバーへ送る
```

攻撃者が自分のサイトにアクセスさせ、ユーザーのクッキーを使って機密情報を読み取り、自分のサーバーに送信する――  
**これを防ぐのがCORSの役割です。**


## 🧱 CORSエラーの仕組みと回避方法

ブラウザはレスポンスヘッダに **`Access-Control-Allow-Origin`** が含まれているかをチェックし、**許可されたオリジンではない場合、JavaScript からのアクセスを遮断**します。

例：
```
Access-Control-Allow-Origin: https://example.com
```


### ⚠️ 注意点：

- `Access-Control-Allow-Origin: *` は「どんなオリジンでも通します」という意味になるため、本番環境ではNG（特にクッキーなどの**認証情報**を扱う場合は非常に危険）。  
  一方で、開発中にローカルから確認するようなケースでは、手軽さを優先してOK。
- **APIは、リクエスト自体を受け取ってレスポンスも返しているが、JS側では「アクセス不可」となる**。  
- サーバー同士の通信にはCORS制約は関係ない（＝fetchなどJS経由の話）。  

つまり、**APIを「ブラウザから呼び出す」なら、必ずCORS対応が必要**になります。

:::note info
**補足：Access-Control-Allow-Origin の値はどう決まる？**  
一部の実装では、リクエストヘッダの `Origin` を見て「この値なら返す、そうでなければ返さない」と**動的に判断する仕組み**を取っていることもあります。  
最近のSaaS系サービスでは、CORSの制御はインフラや設定画面で完結することも多く、**アプリ側でCORSヘッダを動的に組み立てるケースは減ってきています**。
:::


## ✈️ プリフライトリクエストとは？

一部のCORSリクエストでは、ブラウザが「**このリクエスト送ってもいい？**」と事前確認を行います。これを**プリフライト（preflight）リクエスト**と呼びます。

### プリフライトが発生する例：

- `Content-Type: application/json` を指定  
- カスタムヘッダ（例：`X-Requested-With`など）を使用  
- `PUT` や `DELETE` などの一部HTTPメソッドを使用  

プリフライトリクエストに対して **200 OK** など 成功ステータスが返ってこないと、本リクエストも送信されません。


## ❗️ CORSが守って「いない」もの

重要なのは、**CORS は API 自体を守っているわけではない**という点です。

以下のようなリクエストは、CORS があっても**実際に API に到達してしまいます**：

```js
fetch("https://example.com/api/deleteBankAccount", {
  method: "POST",
  credentials: "include"
});
```
これは **APIサーバー側のロジックで制限しないと実行され得る** ため、CORSとは別に適切な認証・認可を設計する必要があります。  
たとえば、以下のような対策があります：

- CSRFトークン  
- Refererチェック  
- SameSite Cookie設定  
- アクセス制御ロジック（IP制限など）  

:::note info
 **補足：非GETリクエストも、CORSによって結果的に守られている場合がある**  
たとえば `POST` や `DELETE` のような非GET系のリクエストは、多くの場合プリフライト（事前確認）が発生し、  
**そのプリフライトに失敗することで本リクエスト自体が行われない**というケースもあります。  
ただし、それでもCORSは完全な防御ではないため、**CSRFトークンなど多重防御は重要**です。
:::



## ✅ まとめ

- CORSはあくまで「**読み取りを制限するブラウザ機能**」である  
- 認証情報を悪用される読み取り型の攻撃を防ぐのが目的  
- 本質的なAPI防御には**別途サーバー側の防御ロジックが必要**  
- 「なんかCORSエラー出た」というときに、仕組みと目的がわかっていると対処がスムーズ！


「"CORS＝邪魔なエラー" と感じがちだけど、実はユーザーを守るための仕組み」という視点を持つと、CORSとの付き合い方が少し優しくなるかもしれません。

以上です！