Web開発を学んでいると、「ログイン状態をどうやって保持しているのか」という疑問に突き当たることがあります。答えは「Cookie」と「Session」という仕組みにあります。

この記事では、HTTP通信がステートレスである理由から始まり、CookieとSessionの違い、Cookieの重要な属性(HttpOnly, Secure, SameSite)、そしてサーバーサイドSessionの仕組みまでを図解で解説します。開発者ツールでCookieやSessionを確認する方法も紹介しますので、実際に手を動かしながら理解を深めてください。

HTTP通信がステートレスである理由

HTTP(HyperText Transfer Protocol)は「ステートレス(stateless)」なプロトコルとして設計されています。ステートレスとは、各HTTPリクエストが独立しており、前のリクエストの状態を保持しないという特性です。

ステートレスの仕組み

sequenceDiagram
    participant Browser as ブラウザ
    participant Server as サーバー
    Note over Browser,Server: 1回目のリクエスト
    Browser->>Server: GET /index.html
    Server-->>Browser: 200 OK + HTML
    Note over Browser,Server: 2回目のリクエスト(サーバーは1回目を覚えていない)
    Browser->>Server: GET /about.html
    Server-->>Browser: 200 OK + HTML
    Note over Server: サーバーは2回目のリクエストが<br>同じユーザーかどうか判別できない

なぜHTTPはステートレスなのか

HTTPがステートレスに設計された理由は以下の通りです。

  1. シンプルさ: サーバーが状態を管理する必要がないため、実装がシンプルになります
  2. スケーラビリティ: 状態を保持しないため、リクエストを任意のサーバーで処理できます(ロードバランシングが容易)
  3. 信頼性: 状態を失っても次のリクエストに影響しません

ステートレスの課題

しかし、現代のWebアプリケーションでは「ユーザー状態」の管理が必要です。

  • ログイン状態の維持
  • ショッピングカートの保持
  • ユーザー設定の記憶

これらの課題を解決するために登場したのが「Cookie」と「Session」という仕組みです。

Cookieとは何か

Cookieは、Webサーバーがブラウザに送信し、ブラウザがローカルに保存する小さなデータです。ブラウザは同じサーバーへのリクエスト時に、保存したCookieを自動的に送信します。

Cookieの仕組み

sequenceDiagram
    participant Browser as ブラウザ
    participant Server as サーバー
    Note over Browser,Server: 初回リクエスト時
    Browser->>Server: GET /login
    Server-->>Browser: Set-Cookie: user=john
    Note over Browser: Cookieをローカルに保存<br>Cookie: user=john
    Note over Browser,Server: 2回目以降のリクエスト
    Browser->>Server: GET /dashboard<br>Cookie: user=john
    Server-->>Browser: 200 OK
    Note over Server: サーバーはCookieから<br>ユーザーを識別できる

Cookieの設定方法

サーバーはSet-Cookieヘッダーを使ってCookieを設定します。

1
2
3
4
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax
Set-Cookie: theme=dark; Max-Age=31536000

ブラウザはCookieヘッダーを使ってCookieを送信します。

1
2
3
GET /dashboard HTTP/1.1
Host: example.com
Cookie: session_id=abc123; theme=dark

Cookieの用途

Cookieは主に以下の目的で使用されます。

用途 説明
セッション管理 ログイン状態やカート情報の保持 セッションID
パーソナライズ ユーザー設定の記憶 言語設定、テーマ
トラッキング ユーザー行動の分析 アクセス解析

Cookieの重要な属性

Cookieにはセキュリティと動作を制御する複数の属性があります。これらの属性を正しく設定することで、セキュアなWebアプリケーションを構築できます。

Secure属性

Secure属性を設定すると、CookieはHTTPS接続でのみ送信されます。

1
Set-Cookie: session_id=abc123; Secure

この属性により、中間者攻撃(Man-in-the-Middle攻撃)によるセッションIDの盗聴を防止できます。

sequenceDiagram
    participant Browser as ブラウザ
    participant Attacker as 攻撃者
    participant Server as サーバー
    
    Note over Browser,Server: Secure属性なしの場合(危険)
    Browser->>Server: HTTPでCookie送信
    Attacker-->>Browser: 盗聴可能
    
    Note over Browser,Server: Secure属性ありの場合(安全)
    Browser->>Server: HTTPSでCookie送信(暗号化通信)
    Note over Attacker: 盗聴不可能

HttpOnly属性

HttpOnly属性を設定すると、JavaScriptからCookieにアクセスできなくなります。

1
Set-Cookie: session_id=abc123; HttpOnly

この属性により、XSS(クロスサイトスクリプティング)攻撃によるセッションIDの窃取を防止できます。

1
2
3
4
5
// HttpOnly属性が設定されていない場合
document.cookie; // "session_id=abc123" が取得可能(危険)

// HttpOnly属性が設定されている場合
document.cookie; // session_id は取得できない(安全)

SameSite属性

SameSite属性は、クロスサイトリクエスト時のCookie送信を制御します。CSRF(クロスサイトリクエストフォージェリ)攻撃の防止に効果的です。

説明 ユースケース
Strict 同一サイトからのリクエストでのみ送信 高セキュリティが必要な認証Cookie
Lax トップレベルナビゲーションでは送信 一般的なセッションCookie(デフォルト)
None すべてのリクエストで送信(Secure必須) サードパーティCookie
1
2
3
4
5
6
7
8
# 認証Cookieの推奨設定
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Strict

# 一般的な設定
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax

# サードパーティ向け(Secure必須)
Set-Cookie: tracking=xyz; SameSite=None; Secure

Domain属性とPath属性

Domain属性とPath属性は、Cookieが送信される範囲を制限します。

1
2
3
4
5
# サブドメインを含むすべてのパスで有効
Set-Cookie: user=john; Domain=example.com; Path=/

# 特定のパスでのみ有効
Set-Cookie: admin_token=xyz; Path=/admin
属性 設定なしの場合 設定ありの場合
Domain 設定元のホストのみ 指定ドメインとサブドメイン
Path 設定元のパスのみ 指定パスとサブパス

Expires属性とMax-Age属性

Cookieの有効期限を設定する属性です。

1
2
3
4
5
# 特定の日時まで有効
Set-Cookie: user=john; Expires=Thu, 31 Dec 2026 23:59:59 GMT

# 1年間有効(秒単位で指定)
Set-Cookie: user=john; Max-Age=31536000
種類 設定 動作
セッションCookie Expires/Max-Age なし ブラウザを閉じると削除
永続Cookie Expires/Max-Age あり 指定期限まで保持

サーバーサイドSessionの仕組み

Sessionは、ユーザーの状態をサーバー側で管理する仕組みです。Cookieがクライアント側にデータを保存するのに対し、Sessionはサーバー側にデータを保存します。

Session管理の流れ

sequenceDiagram
    participant Browser as ブラウザ
    participant Server as サーバー
    participant Store as Session Store
    
    Note over Browser,Server: 1. ログイン時
    Browser->>Server: POST /login<br>username=john
    Note over Server: Session作成<br>ID: sess123<br>user: john
    Server->>Store: sess123: user=john, role=admin
    Server-->>Browser: Set-Cookie: session_id=sess123
    
    Note over Browser,Server: 2. 認証が必要なページへアクセス
    Browser->>Server: GET /dashboard<br>Cookie: session_id=sess123
    Server->>Store: Session検索
    Store-->>Server: user: john, role: admin
    Note over Server: 認証済みと判断
    Server-->>Browser: 200 OK

Sessionデータの保存場所

Sessionデータはサーバー側の様々な場所に保存できます。

保存場所 特徴 適したケース
メモリ 高速だがサーバー再起動で消失 開発環境
ファイル シンプルだがスケールしにくい 小規模アプリ
データベース 永続化可能だがオーバーヘッド 中規模アプリ
Redis/Memcached 高速かつ分散可能 大規模アプリ

Session実装例(Node.js + Express)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const express = require('express');
const session = require('express-session');

const app = express();

// Session設定
app.use(session({
  secret: 'your-secret-key',      // 署名用の秘密鍵
  resave: false,                   // 変更がなくても再保存するか
  saveUninitialized: false,        // 初期化前のSessionを保存するか
  cookie: {
    httpOnly: true,                // HttpOnly属性
    secure: true,                  // Secure属性(HTTPS必須)
    sameSite: 'lax',               // SameSite属性
    maxAge: 24 * 60 * 60 * 1000    // 有効期限(24時間)
  }
}));

// ログイン処理
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  
  // 認証処理(簡略化)
  if (username === 'john' && password === 'secret') {
    req.session.user = { name: username, role: 'admin' };
    res.redirect('/dashboard');
  } else {
    res.status(401).send('認証失敗');
  }
});

// 認証が必要なページ
app.get('/dashboard', (req, res) => {
  if (req.session.user) {
    res.send(`ようこそ、${req.session.user.name}さん`);
  } else {
    res.redirect('/login');
  }
});

// ログアウト処理
app.post('/logout', (req, res) => {
  req.session.destroy((err) => {
    if (err) {
      res.status(500).send('ログアウト失敗');
    } else {
      res.redirect('/login');
    }
  });
});

CookieとSessionの違い

CookieとSessionは補完的な関係にあります。それぞれの特徴を理解して適切に使い分けましょう。

比較表

項目 Cookie Session
データ保存場所 クライアント(ブラウザ) サーバー
容量制限 約4KB サーバーリソースに依存
セキュリティ クライアントで改ざん可能 サーバーで保護
有効期限 ブラウザで管理 サーバーで管理
ネットワーク負荷 リクエストごとに送信 Session IDのみ送信

使い分けの指針

flowchart TB
    subgraph CookieData["Cookie向きのデータ"]
        C1["ユーザー設定<br>(言語、テーマ)"]
        C2["トラッキング情報"]
        C3["Remember Me機能の<br>トークン"]
    end
    subgraph SessionData["Session向きのデータ"]
        S1["ログイン状態"]
        S2["ユーザー権限情報"]
        S3["ショッピングカート"]
        S4["フォームの一時データ"]
    end

セキュリティの観点から

機密情報は必ずSessionに保存し、CookieにはSession IDのみを保存するのがベストプラクティスです。

flowchart LR
    subgraph Browser["ブラウザ"]
        Cookie["Cookie:<br>sess_id=abc123"]
    end
    subgraph Server["サーバー"]
        Session["Session:<br>user: john<br>role: admin<br>cart: [...]"]
    end
    Cookie -->|Session ID| Session

開発者ツールでCookieとSessionを確認する方法

ブラウザの開発者ツールを使って、CookieとSessionの動作を確認できます。

Chrome DevToolsでの確認手順

  1. 開発者ツールを開く: F12キーまたは右クリックから「検証」を選択
  2. Applicationタブを選択: 上部のタブから「Application」をクリック
  3. Storageセクション: 左サイドバーの「Storage」→「Cookies」を展開
  4. Cookieの確認: サイトごとのCookie一覧が表示される

確認できる情報

Chrome DevTools > Application > Cookies

Name Value Domain Path Expires Size
session_id abc123 example.com / Session 24
theme dark example.com / 2026-12-31 12

各列の意味

列名 説明
Name Cookie名
Value Cookieの値
Domain 有効なドメイン
Path 有効なパス
Expires 有効期限(Sessionは「Session」と表示)
HttpOnly JavaScriptからアクセス不可(チェックマーク)
Secure HTTPSのみ送信(チェックマーク)
SameSite クロスサイト制限(Strict/Lax/None)

NetworkタブでのCookie送受信確認

  1. Networkタブを開く: 開発者ツールで「Network」タブを選択
  2. リクエストを選択: 任意のリクエストをクリック
  3. Headersを確認: Request HeadersとResponse Headersを確認
1
2
3
4
5
# Request Headers
Cookie: session_id=abc123; theme=dark

# Response Headers
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax

Consoleでの確認(HttpOnly以外)

1
2
3
4
// Consoleでの確認(HttpOnly属性がないCookieのみ)
console.log(document.cookie);
// 出力: "theme=dark"
// 注: HttpOnly属性のsession_idは表示されない

Sessionセキュリティのベストプラクティス

安全なWebアプリケーションを構築するために、以下のセキュリティ対策を実装しましょう。

Session IDの要件

flowchart TB
    A["安全なSession IDの特徴"] --> B["十分なエントロピー<br>(最低64ビット)"]
    A --> C["暗号論的擬似乱数生成器<br>(CSPRNG)で生成"]
    A --> D["推測不可能<br>(連番やタイムスタンプ禁止)"]
    A --> E["意味のない値<br>(ユーザー情報を含めない)"]

認証後のSession ID再生成

ログイン成功後は必ずSession IDを再生成して、セッション固定攻撃を防止します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// ログイン成功後のSession ID再生成(Express)
app.post('/login', (req, res) => {
  // 認証成功後
  req.session.regenerate((err) => {
    if (err) {
      return res.status(500).send('セッション再生成エラー');
    }
    req.session.user = { name: username };
    res.redirect('/dashboard');
  });
});

Sessionタイムアウトの設定

1
2
3
4
5
6
7
// Express-sessionでのタイムアウト設定
app.use(session({
  cookie: {
    maxAge: 30 * 60 * 1000,  // 30分(アイドルタイムアウト)
  },
  rolling: true              // アクセスごとに有効期限を延長
}));
タイムアウト種別 推奨値 説明
アイドルタイムアウト 2-5分(高セキュリティ)/ 15-30分(一般) 非アクティブ時間
絶対タイムアウト 4-8時間 セッション最大持続時間

Cookie属性のチェックリスト

セッション管理用Cookieには以下の属性を必ず設定しましょう。

属性 必須 設定値
HttpOnly 必須 常にtrue
Secure 必須(本番) 常にtrue(HTTPS必須)
SameSite 推奨 LaxまたはStrict
Path 推奨 必要最小限のパス

まとめ

CookieとSessionは、ステートレスなHTTP通信においてユーザー状態を管理するための重要な仕組みです。

この記事で学んだ内容を振り返りましょう。

  • HTTP通信は設計上ステートレスであり、各リクエストは独立している
  • Cookieはクライアント側にデータを保存し、リクエストごとに自動送信される
  • Cookie属性(HttpOnly, Secure, SameSite)を正しく設定することでセキュリティを向上できる
  • Sessionはサーバー側でユーザー状態を管理し、CookieにはSession IDのみを保存する
  • 機密情報は必ずサーバーサイドのSessionに保存する
  • 開発者ツールを使ってCookieの送受信を確認できる

次の記事では、セッション管理の実装パターンとセキュリティ対策について、より実践的な内容を解説します。

参考リンク