Cookie とセッション
Cookie でブラウザに小さな印を持たせ、サーバ側セッションと組み合わせてログイン状態を保ちます。属性 HttpOnly / Secure / SameSite の意味まで整理します。
- 1.Cookie はサーバがブラウザに持たせる小さなテキストで、同じサイトへのリクエストに自動で付いて送られる。
- 2.ログイン状態は、サーバにユーザー情報を置き、ブラウザにはセッション ID だけを Cookie で渡す方式が基本。
- 3.HttpOnly / Secure / SameSite の属性が安全性を左右する。最低限この 3 つは付ける。
なぜ Cookie が要るのか
HTTP は ステートレスです。1 回のリクエストとレスポンスで完結し、サーバは前回の通信を覚えていません。だからログインに成功しても、次のページ要求は「初対面」として処理され、誰なのか分からなくなります。
そこで、最初の 1 回だけ本人確認をして、以降は短い合言葉を毎回提示する流れにします。この合言葉をブラウザとサーバの間で持ち回る運び役が Cookie です。
- Cookie は「認証方式」ではなく、データを往復させる運搬手段にすぎない。
- 中に何を入れるか(後述のセッション ID など)が本質。
Cookie の仕組み
Cookie のやり取りは HTTP ヘッダだけで成立します。サーバが Set-Cookie で渡し、ブラウザが次回から Cookie ヘッダで送り返します。
# サーバ → ブラウザ(ログイン成功時)
HTTP/1.1 200 OK
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=3600
# 以降、ブラウザ → サーバ(同じサイト宛に自動で付く)
GET /mypage HTTP/1.1
Cookie: session_id=abc123
ポイントは、一度受け取った Cookie をブラウザが同じサイト宛のリクエストに自動で付け続けることです。開発者が JavaScript で何もしなくても付与されます。この「自動で付く」性質が便利な一方、後述の CSRF というリスクの原因にもなります。
サーバ側セッションとセッション ID
ログイン後の「あなたは誰か」という情報をどこに置くかが設計の分かれ目です。基本形は次のとおりです。
- ユーザー ID や権限などの正体はサーバ側に保存する(メモリ、DB、Redis など)。
- ブラウザには中身のないランダムなセッション ID だけを Cookie で渡す。
- セッション ID は、サーバ内のデータを引くための「ロッカーの鍵」。
この方式なら、ブラウザに渡る Cookie には意味のない文字列しか入らないので、盗み見られても直接は中身が分かりません。また、サーバ側のデータを消せば即座にログアウトを強制できます。
// ログイン:本人確認できたらセッションを作り、ID を Cookie で渡す
app.post("/login", async (req, res) => {
const user = await verifyPassword(req.body.id, req.body.password);
if (!user) return res.status(401).send("Unauthorized");
const sid = createSession(user.id); // サーバ側ストアに sid → user.id を保存
res.cookie("session_id", sid, { httpOnly: true, secure: true, sameSite: "lax" });
res.send("ok");
});
// 保護ページ:届いた Cookie の ID でサーバ側を引き直す
app.get("/mypage", (req, res) => {
const userId = lookupSession(req.cookies.session_id);
if (!userId) return res.status(401).send("Login required");
res.send("Hello user " + userId);
});
主要な属性(HttpOnly / Secure / SameSite)
Cookie の安全性は属性で決まります。最低限おさえるべきものを整理します。
| 属性 | 役割 | ひとこと |
|---|---|---|
HttpOnly | JavaScript(document.cookie)から読めなくする | XSS で盗まれにくくする最重要属性 |
Secure | HTTPS のときだけ送信する | 平文での漏洩を防ぐ |
SameSite | 別サイト発のリクエストに付けない | Lax / Strict で CSRF を緩和 |
Max-Age / Expires | 有効期限を決める | 無指定だとブラウザを閉じるまで(セッション Cookie) |
SameSite には主に 3 つの値があります。Strict は別サイトからの遷移では一切送らず最も厳格、Lax は通常のリンク遷移では送る現実的な既定値、None はクロスサイトでも送る代わりに Secure 必須です。
HttpOnly を付けない Cookie は JavaScript から読めるため、XSS(攻撃者のスクリプトがページ内で実行される攻撃)が成立すると、セッション ID ごと盗まれてなりすましされます。セッション用の Cookie には HttpOnly を必ず付け、加えて XSS そのものを出さない(入力のエスケープ)ことが大前提です。
つまずきポイント:CSRF と有効期限
Cookie が自動で送られる性質は、**CSRF(クロスサイトリクエストフォージェリ)**の温床になります。利用者がログイン中に罠ページを開くと、そこから本物サイトへ勝手にリクエストが飛び、Cookie も自動で付いてしまうためです。
- 対策の基本は
SameSite=Lax(またはStrict)で、別サイト発のリクエストに Cookie を付けないこと。 - 重要操作には別途 CSRF トークンを併用するとさらに堅い。
有効期限の指定も実務では重要です。Max-Age を付けない Cookie はブラウザを閉じると消える(セッション Cookie)ため、「ログイン状態を保持する」チェックの有無で使い分けます。
セッション用 Cookie は HttpOnly + Secure + SameSite=Lax を出発点にし、正体はサーバ側セッションに置く。これだけで、盗み見・盗聴・CSRF の主要リスクをまとめて下げられます。
ステータスコード 401(未認証)と 403(権限なし)の違いなど土台は HTTP を、別オリジンの API を叩く際の制約は CORS もあわせてどうぞ。
Web/フロントエンド Article
Cookie とセッションを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
Cookie
比較で見る軸
難易度: basic / カテゴリ: Web/フロントエンド / タグ数: 4
導入後に効く点
ログイン状態は、サーバにユーザー情報を置き、ブラウザにはセッション ID だけを Cookie で渡す方式が基本。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- basic
- カテゴリ
- Web/フロントエンド
- タグ数
- 4
判断チェックリスト
- 自社の用途が「Cookie / セッション」に近いか確認する。
- 強みである「Cookie はサーバがブラウザに持たせる小さなテキストで、同じサイトへのリクエストに自動で付いて送られる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。