ログイン処理を実装するたびに「Cookieってどうだったっけ?」と調べ直してしまうことがよくあります。
便利な仕組みでありながら、セキュリティやクロスオリジンの挙動など覚えることも多く、毎回少しずつ忘れてしまう...。\
そして複数のシステムのやり取りを考えるとき、Cookieの考え方がないと成り立たないときがあります。
そんな自分のために、Cookieの基本と実務で迷いやすいポイントをまとめてみました。
Cookieとは?
Cookieは ブラウザに保存されるキーバリュー形式のテキストデータ
です。
仕組みはシンプルで、次のような流れになります。
- サーバーがレスポンスに
Set-Cookieヘッダを付ける\ - ブラウザがCookieを保存する\
- 以降、そのドメインにリクエストするとブラウザが自動的にCookieを送信してくれる
たとえば次のように返すと...
Set-Cookie: sid=abc123; Path=/; Domain=.example.com; HttpOnly; Secure; SameSite=Lax
ブラウザはこの情報を記録し、以後 example.com
配下へのアクセス時に自動的に Cookie: sid=abc123 を付与します。
この「自動で送られる」という便利さが、ログイン状態の維持を可能にする一方で、CSRF攻撃の原因にもなるわけです。
よく使われる属性とその意味
Cookieにはさまざまな属性があり、挙動をコントロールできます。実務で特によく出てくるのは次の4つです。
-
Domain / Path
Cookieをどのドメイン・パスに送るかを決めます。
例:Domain=.qiita.comにするとid.qiita.comやwww.qiita.com
でもCookieが送られます。
サブドメイン全体でログイン状態を共有できる反面、範囲を広げすぎるとリスクが増える点に注意です。
最近のサービスはドメインの前に.をつけてCookieを作ることでサブドメインにも送信できるようにしてるのをよく見ます。
-
HttpOnly
JavaScriptのdocument.cookieからアクセスできなくなる設定です。
もしXSSでスクリプトが仕込まれても、Cookieを直接盗まれることを防げます。セッションIDやトークンには必ず付けるべき。 -
SameSite
クロスサイトリクエスト時にCookieを送るかどうかを制御します。
デフォルトはLax
で、GET遷移では送られるがPOSTやXHRでは送られにくい。
他ドメインに送る必要がある場合はNoneにしますが、その場合
必ずSecureが必須 になります。 -
Secure
HTTPS通信のときだけCookieを送るようにする設定です。
実務では基本的に常につける、と覚えておけば安全です。
クロスオリジン通信での注意点
APIサーバーを別ドメインで用意している場合など、フロントエンドからCookieを送信したいことがあります。
このとき注意すべきポイントは以下の通りです。
- フロントエンドのfetchでは必ず
credentials: "include"を指定する\ - サーバー側も
Access-Control-Allow-Credentials: true
を返す必要がある\ -
Access-Control-Allow-Originは*ではなく具体的なオリジンを指定する
例:
fetch("https://api.example.com/data", {
method: "GET",
credentials: "include"
});
さらにCookie側でも、クロスオリジンで送るには SameSite=None; Secureを必ずセットする必要があります。
つまり「クロスオリジンでCookieを使うときはHTTPS必須」と覚えておくと分かりやすいです。
ドメイン設計の実例
たとえばYouTubeでログインすると、Domain=.youtube.comのCookieが発行されます。
その結果、music.youtube.comにアクセスしたときにも同じCookieが送信されるため、再ログインせずにYouTube
Musicが使えるのです。
便利な仕組みですが、範囲を広げすぎるとリスクも広がります。開発用サブドメインや管理系サブドメインにまで届くと危険なので、必要最小限にとどめるのが鉄則です。
開発者ツールでの見え方
ChromeのDevToolsのApplicationタブでは「今アクセスしているオリジン」のCookieしか見えません。
そのため「music.youtube.comでCookieを見てもwww.youtube.comのCookieが無い!」と思うかもしれません。
しかし実際にはブラウザ内部で保持されており、Networkタブでwww.youtube.com宛のリクエストを確認すると、ちゃんと共通のCookieが送られているのが確認できます。
サーバー間でのCookie受け渡し
ブラウザは自動でCookieを付与してくれますが、Next.js のサーバー側からバックエンドAPIへリクエストする場合は、自分で Cookie ヘッダを付ける必要があります。
例えばユーザーがログイン済みの状態で、music.example.com から api.example.com へアクセスしたいケースを考えます。
Next.js (App Router) では next/headers の cookies() を使って現在のリクエストのCookieを取り出し、それをそのままAPIに渡すのが基本です。
// app/api/proxy/route.ts (Next.js 13+ App Router の例)
import { cookies } from "next/headers";
export async function GET() {
// 現在のリクエストに含まれるCookieを取得
const cookieStore = cookies();
const cookieHeader = cookieStore.toString(); // "sid=abc123; theme=dark" のような文字列に変換
// 取得したCookieをそのままAPIに転送
const res = await fetch("https://api.example.com/user", {
method: "GET",
headers: {
Cookie: cookieHeader,
},
// クロスオリジンでもCookieを受け渡すなら必須
credentials: "include",
});
const data = await res.json();
return Response.json(data);
}
実務的にほとんどテンプレのセット
認証やセッション管理で使う Cookie は、どんな状況でも基本的にこの3点セットが必須です。
- HttpOnly → JSから参照できなくする(XSS対策)
- Secure → HTTPSでのみ送信(盗聴対策)
- SameSite → CSRF対策のために必ず指定する
ここまでは 同一オリジンでもクロスオリジンでも共通 です。
そしてクロスオリジン通信を許可したい場合は、さらに条件がつきます。
- SameSite を
Noneにする - その場合は必ず
Secureが必須(HTTPでは動作しない)
まとめると
-
同一オリジン:
HttpOnly; Secure; SameSite=Lax(または Strict) -
クロスオリジン:
HttpOnly; Secure; SameSite=None
おわりに
Cookieは「サーバーが発行し、ブラウザが条件に応じて自動で送信する」という仕組みで成り立っています。
その挙動は DomainやPathの設計、SameSiteやSecureといった属性、そして ブラウザごとの扱い に強く影響されます。
今回まとめたように、
- Cookieはブラウザがどのように保存・送信しているのか
- ドメインやサブドメインをまたぐときにどんな挙動になるのか
- クロスオリジン通信では何が必要になるのか
といった「仕組み」と「設計の工夫」を理解しておけば、セッション管理やログイン実装のときに迷いが少なくなります。
セキュリティももちろん大事ですが、それ以上に 「なぜ自動で送られるのか」「なぜドメインを広げすぎると危険なのか」 を理解することで、Cookieという仕組み自体を正しく捉えられるはずです。
次にログイン機能やAPI通信を実装するときには、この仕組みを思い出して設計に活かしていきたいと思います。
