Cookie の仕組み - Set-Cookie / SameSite / Secure / HttpOnly

入門 | 11分 で読める | 2026.05.02

公式ドキュメント

この記事の要点

Cookieはサーバーがブラウザにデータを保存し、次回以降のリクエストで自動送信される仕組み
Set-Cookieヘッダーでサーバーが保存し、Cookieヘッダーでブラウザが送信
SameSite=Laxがデフォルトで、CSRF攻撃を防ぐ重要な防御策

Cookieとは

Cookieは、サーバーがブラウザに保存を依頼する小さなテキストデータです。HTTPはステートレス(状態を持たない)なため、Cookieを使ってセッション管理、ユーザー識別、設定の保存などを実現します。

なぜ必要か: HTTPリクエストは独立しており、「前回ログインしたユーザー」を識別できません。Cookieがあることで、サーバーは「このリクエストは誰からか」を判断できます。

Cookieの基本フロー

ログイン成功時など、サーバーがCookieをブラウザに保存します。

HTTP/1.1 200 OK
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=3600
Content-Type: text/html

次回以降、同じドメインへのリクエストには自動的にCookieが付与されます。

GET /dashboard HTTP/1.1
Host: example.com
Cookie: sessionId=abc123
// サーバー側(Node.js例)
app.get('/dashboard', (req, res) => {
  const sessionId = req.cookies.sessionId;
  const user = sessions[sessionId];
  
  if (user) {
    res.send(`Welcome, ${user.name}!`);
  } else {
    res.redirect('/login');
  }
});

ポイント: CookieはブラウザがHTTPヘッダーで自動送信します。JavaScriptで明示的に送る必要はありません(HttpOnly属性があればJSからアクセスもできません)。

サーバーがCookieを送信する際、さまざまな属性で動作を制御できます。

属性説明
DomainCookieが送信されるドメインDomain=example.com
PathCookieが送信されるパスPath=/api
Expires有効期限(日時)Expires=Wed, 21 Oct 2026 07:28:00 GMT
Max-Age有効期限(秒数)Max-Age=3600 (1時間)
SecureHTTPS通信でのみ送信Secure
HttpOnlyJavaScriptからアクセス不可HttpOnly
SameSiteクロスサイトリクエストでの送信制御SameSite=Strict / Lax / None

完全な例

Set-Cookie: sessionId=abc123; Domain=example.com; Path=/; Max-Age=86400; Secure; HttpOnly; SameSite=Lax

意味:

  • sessionId=abc123: Cookieの名前と値
  • Domain=example.com: example.comとサブドメインに送信
  • Path=/: 全てのパスに送信
  • Max-Age=86400: 24時間有効
  • Secure: HTTPSのみ
  • HttpOnly: JavaScript不可
  • SameSite=Lax: クロスサイトGETは送信、POSTは不送信

SameSite 属性の詳細

CSRF(Cross-Site Request Forgery)攻撃を防ぐ最重要属性です。

クロスサイトGETクロスサイトPOST用途
Strict送信しない送信しない最高セキュリティ(使いにくい)
Lax送信する送信しないデフォルト・推奨
None送信する送信するサードパーティCookie(要Secure)

Strict

Set-Cookie: sessionId=abc123; SameSite=Strict

動作:

  • example.com内のリンククリック → Cookie送信
  • other.comからexample.comへのリンク → Cookie送信しない

問題点: 外部サイトからのリンクでログイン状態が解除されたように見える。

Lax(推奨)

Set-Cookie: sessionId=abc123; SameSite=Lax

動作:

  • example.com内のリンク → Cookie送信
  • other.comからexample.comへのGETリンク → Cookie送信
  • other.comからexample.comへのPOST → Cookie送信しない

利点: ユーザビリティとセキュリティのバランスが良い。CSRF攻撃の大半を防げる。

None(サードパーティCookie)

Set-Cookie: trackingId=xyz789; SameSite=None; Secure

動作: 全てのクロスサイトリクエストで送信。

用途:

  • 広告トラッキング
  • 埋め込みコンテンツ(YouTube埋め込み等)
  • OAuth/SSOプロバイダー

必須条件: Secure属性が必要(HTTPSのみ)。

注意: SameSite=Noneには必ずSecure属性が必要です。HTTPでは動作しません。また、ブラウザのサードパーティCookie廃止方針により、今後使用が制限されます。

Secure 属性と HttpOnly 属性

Secure

Set-Cookie: sessionId=abc123; Secure

効果: HTTPS通信でのみCookieを送信。HTTP通信では送信されない。

用途: セッションID、認証トークンなど機密情報には必須。

HttpOnly

Set-Cookie: sessionId=abc123; HttpOnly

効果: document.cookieでJavaScriptからアクセスできない。

用途: XSS(Cross-Site Scripting)攻撃でのCookie盗難を防ぐ。

例(攻撃の防御):

// HttpOnlyがない場合、XSS攻撃でCookieを盗める
console.log(document.cookie); // sessionId=abc123

// HttpOnlyがある場合
console.log(document.cookie); // sessionIdは表示されない

ポイント: セッションCookieにはHttpOnly + Secure + SameSite=Laxの3点セットが基本です。

Domain と Path の動作

Domain 属性

Set-Cookie: token=abc; Domain=example.com

送信される範囲:

  • example.com → ✓
  • www.example.com → ✓(サブドメインも含む)
  • api.example.com → ✓
  • other.com → ✗

省略した場合: 設定元のホストのみ(サブドメインは含まない)。

Set-Cookie: token=abc
# www.example.comで設定した場合

送信される範囲:

  • www.example.com → ✓
  • example.com → ✗
  • api.example.com → ✗

Path 属性

Set-Cookie: token=abc; Path=/api

送信されるパス:

  • /api → ✓
  • /api/users → ✓
  • / → ✗
  • /dashboard → ✗

デフォルト: 設定元のパス。通常はPath=/で全体に送信。

Expires と Max-Age の使い分け

Max-Age(推奨)

Set-Cookie: sessionId=abc; Max-Age=3600

効果: 現在時刻から3600秒(1時間)後に期限切れ。

利点: 相対時間なので、サーバー・ブラウザの時刻ずれの影響を受けない。

Expires

Set-Cookie: sessionId=abc; Expires=Wed, 21 Oct 2026 07:28:00 GMT

効果: 指定日時に期限切れ。

欠点: サーバーとブラウザの時刻がずれていると、意図しない動作になる。

セッションCookie

Set-Cookie: tempData=xyz

有効期限を指定しないと、ブラウザを閉じるまで有効な「セッションCookie」になります。

実践メモ: Max-Age=0でCookieを即座に削除できます。ログアウト処理で使います。

制限項目上限
1つのCookieサイズ約4KB
1ドメインあたりのCookie数約50〜180個(ブラウザ依存)
全Cookie合計サイズ約4KB × Cookie数

注意点:

  • 大きなデータはCookieではなくlocalStoragesessionStorageを使う
  • Cookieが多いとHTTPヘッダーが肥大化してパフォーマンス低下

実装例

Express.js(Node.js)

const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();

app.use(cookieParser());

// ログイン時にCookie設定
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  
  // 認証成功したと仮定
  const sessionId = generateSessionId();
  sessions[sessionId] = { username };
  
  res.cookie('sessionId', sessionId, {
    httpOnly: true,
    secure: true,
    sameSite: 'lax',
    maxAge: 24 * 60 * 60 * 1000 // 24時間(ミリ秒)
  });
  
  res.json({ success: true });
});

// Cookieを読み取り
app.get('/profile', (req, res) => {
  const sessionId = req.cookies.sessionId;
  const user = sessions[sessionId];
  
  if (!user) {
    return res.status(401).json({ error: 'Not authenticated' });
  }
  
  res.json({ username: user.username });
});

// ログアウト時にCookie削除
app.post('/logout', (req, res) => {
  res.clearCookie('sessionId', {
    httpOnly: true,
    secure: true,
    sameSite: 'lax'
  });
  res.json({ success: true });
});

生のHTTPレスポンス

HTTP/1.1 200 OK
Set-Cookie: sessionId=a1b2c3d4; HttpOnly; Secure; SameSite=Lax; Max-Age=86400; Path=/
Set-Cookie: theme=dark; Max-Age=31536000; Path=/
Set-Cookie: lang=ja; Max-Age=31536000; Path=/

複数のSet-Cookieヘッダーで複数のCookieを設定できます。

クライアント側(JavaScript)

// HttpOnlyではないCookieのみアクセス可能
console.log(document.cookie); // "theme=dark; lang=ja"

// JavaScriptでCookie設定(非推奨、セキュリティリスク)
document.cookie = "preference=compact; max-age=3600";

// 推奨: サーバーにSet-Cookieで設定してもらう
fetch('/api/set-preference', {
  method: 'POST',
  credentials: 'include', // Cookieを含める
  body: JSON.stringify({ theme: 'dark' })
});

注意: JavaScriptでdocument.cookieにセッションIDを保存するのは危険です。XSS攻撃で盗まれます。必ずHttpOnly属性付きでサーバーから設定しましょう。

CSRF攻撃と対策

CSRF攻撃の例

攻撃サイト(evil.com):

<form action="https://bank.com/transfer" method="POST">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="10000">
</form>
<script>document.forms[0].submit();</script>

SameSite=Noneの場合: ユーザーが攻撃サイトを訪問すると、bank.comへのPOSTにCookieが自動送信され、送金が実行される。

SameSite=Laxの場合: クロスサイトのPOSTリクエストにCookieが送信されず、攻撃失敗。

追加の対策

  1. CSRFトークン:
// サーバーが発行
res.cookie('csrfToken', generateToken(), { sameSite: 'lax' });

// クライアントがヘッダーで送信
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': getCookie('csrfToken')
  }
});
  1. Referer検証:
app.post('/transfer', (req, res) => {
  const referer = req.headers.referer;
  if (!referer || !referer.startsWith('https://bank.com')) {
    return res.status(403).json({ error: 'Invalid request' });
  }
  // 処理続行
});

サードパーティCookieの廃止

Chrome、Safari、Firefoxはプライバシー保護のため、サードパーティCookie(SameSite=None)を段階的に廃止しています。

影響を受けるサービス:

  • 広告トラッキング
  • ソーシャルログイン(一部)
  • 埋め込みコンテンツの認証

代替手段:

  • CHIPS(Cookies Having Independent Partitioned State): パーティション化Cookie
  • FedCM(Federated Credential Management): ブラウザ標準のID連携
  • Storage Access API: ユーザー承認で限定的にアクセス

ポイント: ファーストパーティCookie(自社ドメイン内)は影響を受けません。SameSite=Laxで適切に設計すれば、サードパーティCookie廃止後も問題ありません。

デバッグとトラブルシューティング

Chrome DevTools で確認

  1. Application タブ → Cookies

    • 全Cookieの一覧、属性、値を確認
    • 手動で削除・編集可能
  2. Network タブ → Response Headers

    • Set-Cookieヘッダーを確認
    • 警告があれば表示される(例: SameSite=None without Secure

よくある問題

Cookie が送信されない:

  • Domain/Path が一致しているか確認
  • Secure属性がHTTP通信で使われていないか
  • SameSite=Strictでクロスサイトアクセスしていないか

Cookie が保存されない:

  • ブラウザの容量制限に達していないか
  • Max-AgeやExpiresが過去になっていないか
  • サードパーティCookieがブロックされていないか

ベストプラクティス

セッション管理

Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=86400; Path=/
  • HttpOnly: XSS対策
  • Secure: 盗聴対策
  • SameSite=Lax: CSRF対策
  • Max-Age: 適切な期限(24時間など)

ユーザー設定

Set-Cookie: theme=dark; Max-Age=31536000; Path=/
  • HttpOnlyは不要(JavaScriptで読み取りたい)
  • 長期保存(1年など)

トラッキング(非推奨)

Set-Cookie: trackingId=xyz; SameSite=None; Secure; Max-Age=31536000

プライバシー規制により、今後は使用を避けるべき。

まとめ

Cookieは、HTTPのステートレスな性質を補完し、Webアプリケーションのセッション管理を実現する重要な仕組みです。HttpOnlySecureSameSite=Laxの3つの属性を適切に設定することで、XSSやCSRF攻撃からユーザーを守ることができます。サードパーティCookieの廃止を見据え、ファーストパーティCookieを基本とした設計を心がけましょう。

参考リソース

この技術を体系的に学びたいですか?

未来学では東証プライム上場企業のITエンジニアが24時間サポート。月額24,800円から、退会金0円のオンラインIT塾です。

メールで無料相談する
← 一覧に戻る