クッキーとは? — HTTPの状態管理
このトピックを完了すると、以下のことができるようになります。
HTTPが「ステートレス」なプロトコルである理由を理解し、クッキーがどのようにこの問題を解決するかを説明し、Expressでクッキーを設定および読み取る方法を理解します。
HTTPにはメモリがない
HTTPプロトコルはステートレスです。リクエストを処理した後、サーバーはクライアントを完全に忘れてしまいます。
クライアント: GET /page1 → サーバー: "Page 1の内容はこちらです"
クライアント: GET /page2 → サーバー: "あなたは誰ですか?はじめまして。Page 2の内容はこちらです"サーバーは、1秒前に/page1をリクエストしたブラウザが、同じユーザーであるかどうかを判断できません。「過去のリクエストを記憶する」ような機能(ログイン、ショッピングカート、ダークモード設定など)は、このステートレスな性質のために不可能です。
クッキーは、この問題を解決します。これは、サーバーがクライアントに「この情報を保存し、次回アクセスしたときに私に見せてください」と言うようなものです。
クッキーの仕組み
クッキーはHTTPヘッダーを通じて交換されます。
1. サーバー → クライアント(レスポンスヘッダー)
Set-Cookie: username=Hoon; Path=/
2. クライアント → サーバー(次のリクエストのリクエストヘッダー)
Cookie: username=Hoon設定されると、ブラウザはクッキーを同じドメインへのすべてのリクエストに自動的に含めます。サーバーが要求しなくても、ブラウザはそれを送信します。これがクッキーの基本的な仕組みです。
Expressでのクッキーの処理
クッキーの設定
const express = require('express');
const app = express();
app.get('/login', (req, res) => {
// Set-Cookieヘッダーを送信
res.cookie('username', 'Hoon', {
maxAge: 24 * 60 * 60 * 1000, // 1日(ミリ秒)
httpOnly: true,
secure: false, // HTTPS経由でのみ送信(開発中はfalseに設定)
sameSite: 'lax'
});
res.json({ message: 'ログインしました。クッキーを設定しました' });
});クッキーの読み取り
クッキーを読み取るには、cookie-parserミドルウェアが必要です。
npm install cookie-parserconst cookieParser = require('cookie-parser');
app.use(cookieParser());
app.get('/profile', (req, res) => {
const username = req.cookies.username;
if (!username) {
return res.status(401).json({ error: 'ログインしていません' });
}
res.json({ message: `ようこそ、${username}さん` });
});cookie-parserは、Cookieヘッダーを解析し、req.cookiesオブジェクトを作成します。このミドルウェアがない場合、ヘッダーを自分で解析する必要があります。
クッキーの削除
app.get('/logout', (req, res) => {
res.clearCookie('username');
res.json({ message: 'ログアウトしました。クッキーをクリアしました' });
});clearCookieは、同じ名前のクッキーをすぐに期限切れにします。
クッキー属性
| 属性 | 説明 | 例 |
|---|---|---|
maxAge | 生存期間(ミリ秒)。この時間が経過すると、クッキーは自動的に削除されます | 86400000(1日) |
expires | 期限切れの日付(Dateオブジェクト)。maxAgeよりも一般的に使用されません | new Date('2026-12-31') |
httpOnly | JavaScriptからアクセスできません(XSS対策の鍵) | true |
secure | HTTPS接続でのみ送信されます | true |
sameSite | 他のサイトからのリクエストにクッキーを含めるかどうか | 'strict', 'lax', 'none' |
path | このパス以下のパスに対してのみ、クッキーが送信されます | '/' |
domain | クッキーが有効なドメイン | '.example.com' |
これらの属性の中で、httpOnlyとsecureはセキュリティにとって最も重要です。
セキュリティ — クッキーを安全に保つ
httpOnly
// 悪い — クッキーはJavaScriptからアクセスできます(XSS脆弱性)
res.cookie('token', 'abc123');
// 良い — JavaScriptからアクセスできません
res.cookie('token', 'abc123', { httpOnly: true });httpOnly: trueを設定すると、document.cookieを使用してクッキーを読み取ることができなくなります。XSS攻撃者がスクリプトを挿入しても、クッキーを盗むことはできません。これは、認証関連のクッキーには常に設定する必要があります。
secure
res.cookie('token', 'abc123', {
httpOnly: true,
secure: true // HTTPS経由でのみ送信
});クッキーは、HTTP(暗号化されていない)接続経由で送信されません。攻撃者はクッキーを傍受できません。
sameSite
res.cookie('token', 'abc123', {
httpOnly: true,
secure: true,
sameSite: 'strict' // 同じサイトからのリクエストでのみ送信
});| 値 | 動作 |
|---|---|
'strict' | クッキーは、同じサイトからのリクエストにのみ含まれます。完全にCSRFをブロックします。ただし、ユーザーが外部リンクからサイトにアクセスすると、ログアウトします。 |
'lax' | GETリクエスト(リンクのクリック)は許可しますが、POSTリクエストはブロックします。CSRF保護と使いやすさの妥協点です。推奨。 |
'none' | すべてのリクエストに含まれます。secure: trueが必要です。クロスサイトAPIでのみ使用されます。 |
クッキーとlocalStorage
| クッキー | localStorage | |
|---|---|---|
| サーバーに送信される | すべてのリクエストに自動的に含まれる | 送信されない |
| サイズ | 約4KB | 約5MB |
| 有効期限 | 自動的に期限切れになる | 手動で削除されるまで |
| アクセス | httpOnlyが設定されている場合、JavaScriptからアクセスできません | JavaScriptからのみアクセス可能 |
| 使用例 | 認証、セッション、サーバー設定 | UIの状態、キャッシュ、オフラインデータ |
「サーバーが知っておく必要のある情報」にはクッキーを使用し、「ブラウザのみが知っておく必要のある情報」にはlocalStorageを使用します。
実際のパターン — ダークモードクッキー
// ダークモードの設定 — サーバーサイドレンダリング中に適用できます
app.post('/settings/theme', (req, res) => {
const { theme } = req.body; // 'dark'または'light'
res.cookie('theme', theme, {
maxAge: 365 * 24 * 60 * 60 * 1000, // 1年
httpOnly: false, // CSSを適用するにはJavaScriptアクセスが必要です
sameSite: 'lax'
});
res.json({ theme });
});
app.get('/', (req, res) => {
const theme = req.cookies.theme || 'light';
res.render('index', { theme });
});ダークモードなどのセキュリティに敏感でない設定では、httpOnly: falseを設定できます。ただし、認証トークンにはhttpOnly: falseを設定しないでください。
主要なポイント
| 概念 | 概要 |
|---|---|
| HTTPステートレス | サーバーは過去のリクエストを記憶しません |
| クッキー | サーバーがクライアントに保存するように要求する小さなデータ |
| Set-Cookie | サーバー → クライアント(レスポンスヘッダー) |
| Cookie | クライアント → サーバー(リクエストヘッダー、自動) |
| httpOnly | JavaScriptからのアクセスを防止します(XSS対策) |
| secure | HTTPS経由でのみ送信されます |
| sameSite | CSRF保護(laxを推奨) |
クッキーは、Webにおける最も古い状態管理メカニズムの1つですが、現在でも広く使用されています。セッション、認証、ユーザー設定など、これらはすべてクッキーに基づいています。セキュリティ属性(httpOnly、secure、sameSite)を設定し忘れると、XSSおよびCSRF攻撃に対して脆弱になるため、クッキーを設定する際には、常にこれら3つを確認してください。
本番環境チェックリスト
認証クッキーを設定する場合は、次の項目を確認してください。
res.cookie('session_token', token, {
httpOnly: true, // ✓ XSS対策 — JavaScriptからのアクセスを防止
secure: true, // ✓ HTTPSのみ — 暗号化されていないテキストでの送信を防止
sameSite: 'lax', // ✓ CSRF対策 — クロスサイトPOSTリクエストをブロック
maxAge: 3600000, // ✓ 有効期限を設定 — 永続的なクッキーを防止
path: '/' // ✓ パスを制限 — 必要な範囲に制限
});これらのいずれかを忘れると、セキュリティ上の脆弱性が生じます。本番環境にデプロイする前に、このチェックリストを確認してください。