# ch01 — Cookie / Session / Stateless HTTP の限界

Source: https://php-school.pages.dev/topics/session-cookie/ch01-what-is-session/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: セッション・Cookie・ログイン
Level: L4

Reference (official): https://www.php.net/manual/ja/book.session.php

## 本文

# ch01 — Cookie / Session / Stateless HTTP の限界

## 概要

HTTP には **「前のリクエストを覚えていない」** という性質がある (Stateless)。サーバーは届いたリクエストに 1 通ずつ返事するだけで、「さっきの人」と「今の人」が同じか **デフォルトでは分からない**。これだとログインも買い物カゴも成立しない。Web は後付けで **「リクエストをまたいで状態を保つ仕組み」** を発明した。それが **Cookie と Session**。

**Cookie** は「サーバーが発行してブラウザに保管してもらう小さなメモ」。一度発行すると、ブラウザは同じサイトに行く度に **そのメモを `Cookie:` ヘッダに乗せて自動で送り返してくる**。これでサーバーは「あ、さっきの人だ」と認識できる。ただ Cookie にユーザー名やパスワードを直接書くのは危険。

そこで **Session**。「ブラウザに渡すのは識別子 (Session ID) だけ、本体のデータはサーバー側に保管」する仕組み。`PHPSESSID` という Cookie に長いランダム文字列が入り、これが **入場券の番号**。サーバー側にはその番号に対応するロッカー (`$_SESSION` 配列) があり、本物のデータはそこに置く。次の章から `session_start()` で実際に動かす。

## 学習目標

- HTTP が **Stateless (前の通信を覚えない)** プロトコルだと言える
- **Cookie** と **Session** の役割の違いを 1 行で説明できる
- **Session ID** がブラウザとサーバーをどう紐付けているかを絵で説明できる

## 所要時間

スライドのみ = **6 分**

## ドリル

**このチャプターにドリルはありません。** スライドを読み終わったら次の `ch02-session-basic/` に進んでください。

理由: ここでは「なぜ Session / Cookie が必要なのか」「両者の役割分担」の **概念の絵** を頭に作るのが目的。手を動かすのは ch02 以降で行います。

## ブラウザで体感してみる (任意)

任意の Web サイト (例: `https://github.com`) を開いて、Chrome の開発者ツール (F12) で:

1. **Application タブ → Cookies** を開く → サイトが発行した Cookie 一覧が見える (`_octo` などの key が並ぶ)
2. **Network タブ** を開いた状態でページをリロードすると、リクエストの `Cookie:` ヘッダにそれらの key が **自動で乗って送られている** ことが分かる
3. ログアウトボタンを押すと、`session` や `auth` 系の Cookie が **消えるか書き換わる** ことが見える

「Session でログインが保たれている」というのは、つまり **Cookie に Session ID が乗って毎回送られている** ということ。次のチャプター以降で、その仕組みを自分の PHP で書く。

## スライド

---
marp: true
theme: dojo
paginate: true
size: 16:9
---

<!--
LLM_CONTEXT:
  Lesson 13 / Chapter 1
  目的: Cookie / Session / Stateless HTTP の絵を頭に作る
  扱わない: session_start (ch02) / setcookie (ch03) / login flow (ch04) / CSRF (ch05) / regenerate_id (ch06)
  読み上げ時間目安: 5 分半〜6 分
-->

# Cookie / Session / Stateless HTTP

Lesson 13 / Chapter 1

---

## HTTP は本来「忘れっぽい」

```
[req1] /login?name=taro   → サーバー: 「OK ログイン」
[req2] /mypage            → サーバー: 「誰だっけ？」
```

- HTTP は **Stateless** = リクエストごとにサーバーはまっさら
- 前のリクエストと繋がりを覚えるには **明示的な仕組み** が要る
- それが **Cookie** (ブラウザに置く) と **Session** (サーバーに置く)

→ Web アプリで「ログイン状態」「カートの中身」を保つには、この 2 つを使う。

---

## Cookie とは

```
[ブラウザ]                           [サーバー]
    │                                    │
    │  ← Set-Cookie: name=taro ─────────│  ← サーバーが渡す
    │                                    │
    │  → Cookie: name=taro ─────────→   │  ← 次回から自動で送る
```

- サーバーが `Set-Cookie:` ヘッダで渡した key=value を **ブラウザが保存** する
- **次回からのリクエストで自動で同じ key=value を送ってくる**
- PHP からは `$_COOKIE['name']` で読める
- **ブラウザ側に保存されるので、ユーザーに改ざんできる** ← 重要

---

## Session とは

```
[ブラウザ]                                  [サーバー]
    │                                          │
    │  ← Set-Cookie: PHPSESSID=ABC123 ────────│
    │                                          │
    │                            $_SESSION = [
    │                              'ABC123' => ['name' => 'taro']
    │                            ]
```

- サーバー側に **連想配列のデータを保存**
- ブラウザには **Session ID (合言葉)** だけ Cookie で渡す
- 次回ブラウザが Session ID を送ってきたら、サーバーは ID で **該当の連想配列** を引く
- **データ本体はサーバー側にあるので、ユーザーに改ざんできない**

---

## Cookie と Session の使い分け

| | Cookie | Session |
|---|---|---|
| 保存場所 | **ブラウザ** | **サーバー** |
| 改ざん | できる | できない |
| 容量 | 小 (1 つ ≦ 4KB 目安) | 大 (サーバーリソース次第) |
| 用途 | 言語設定・テーマ・「次回ログインを保持」など軽い情報 | **ログイン状態**・カート・CSRF トークン |
| PHP からの読み方 | `$_COOKIE['key']` | `$_SESSION['key']` |

→ 「秘密にしたい / 改ざんされたら困る」値は **Session**。それ以外は Cookie。

---

## Session の仕組み (絵)

```
        1. setcookie PHPSESSID
   ┌────────────────────────────────┐
   │                                │
[ブラウザ]                      [サーバー]
   │                                │
   │  2. Cookie: PHPSESSID=ABC123   │
   │ ──────────────────────────→    │
   │                                │
   │                       3. ID で $_SESSION を引く
   │                          → { name: 'taro' }
   │                                │
   │  4. レスポンス本文              │
   │ ←──────────────────────────    │
```

- Session ID は **使い捨ての合言葉**。中身を見ても何の情報も漏れない
- サーバー側で `$_SESSION` をどこに保存するかは設定次第 (ファイル / Redis / DB)

---

## なぜ HttpOnly / Secure / SameSite が要るのか (予告)

| 属性 | 何を防ぐか |
|---|---|
| **HttpOnly** | JavaScript から Cookie が読めないようにする (XSS で Session ID を盗まれにくくする) |
| **Secure** | HTTPS の通信でしか Cookie を送らない (盗聴対策) |
| **SameSite=Lax/Strict** | 他サイトからのリクエストに Cookie を乗せない (**CSRF 対策**) |

→ ch05 で CSRF、ch06 で Session 固定化を扱う。これらは Cookie / Session を使う以上、避けて通れない話。

本格運用は本コースの範囲外だが、**「無防備で使うと攻撃される」** ことだけは知っておく。

---

## このチャプターでできるようになること

✅ HTTP が Stateless であると言える
✅ Cookie はブラウザに保存され改ざん可能、Session はサーバーに保存され改ざん不可、と言える
✅ Session ID が Cookie でブラウザとサーバーを紐付けていると絵で説明できる
✅ HttpOnly / Secure / SameSite の役割を 1 行で言える

関連: ch02 で PHP の `session_start()` と `$_SESSION` で実際に Session を扱う
