# セッション管理とは？ハイジャックを防ぐCookie設定と実装の要点

セッションハイジャックと固定化の仕組み、セッションIDの作り方、Cookie属性、ログイン後の再発行、有効期限、ログアウト時の無効化を、IPA・OWASP・MDNの資料をもとにコード例つきでWeb開発者向けに解説します。

セッション管理は、ログインした利用者をリクエストごとに識別する仕組みです。セッションIDを盗まれたり推測されたりすると、攻撃者はパスワードを知らなくても本人になりすませます。対策の要点は、推測できないIDを使い、Cookieの属性を正しく設定し、ログイン時にIDを作り直し、不要になったセッションをサーバー側で確実に無効化することです。

<Points>

- セッションIDは、ログイン後はパスワードなどの認証情報と同じくらい重要な値になる
- IDは暗号論的に安全な乱数で作り、URLに載せず、`Secure`・`HttpOnly`・`SameSite` を付けたCookieで受け渡す
- ログイン時にIDを作り直し、有効期限とログアウトをサーバー側で処理する

</Points>

## セッション管理とは

HTTPはリクエストごとに独立しているため、ログイン状態を続けるには利用者を識別する値が必要です。多くのWebアプリは、ログイン後にセッションIDを発行してCookieに保存し、以後のリクエストでその値を受け取ります。

OWASPは、認証済みのセッションIDは一時的に、そのアプリで使った最も強い認証方法と同等の値になると説明しています。多要素認証で守ったログインも、後からセッションIDを盗まれれば、その後の操作を乗っ取られるおそれがあります。ログイン自体の守り方は[多要素認証の解説](/multi-factor-authentication/)にまとめています。

## 主な攻撃：推測・盗用・固定化

IPAの「安全なウェブサイトの作り方」は、セッション・ハイジャックに至る手口を3つに分けています。

<Figure title="セッションハイジャックに至る3つの手口" source="IPA「安全なウェブサイトの作り方」セッション管理の不備">

| 手口 | 内容 | 主な対策 |
| --- | --- | --- |
| 推測 | 時刻などから単純な方法で作ったIDを予測する | 暗号論的に安全な乱数でIDを作る |
| 盗用 | 通信やスクリプト、URLの漏えいなどから値を得る | HTTPS、Cookie属性、URLに載せない |
| 固定化 | 攻撃者が用意したIDのまま利用者にログインさせる | ログイン時にIDを作り直す |

</Figure>

固定化は仕組みが少しわかりにくいので、流れで示します。

<Flow
  title="セッション固定化の流れ"
  steps={[
    { label: "攻撃者が用意したIDを利用者に使わせる", note: "ログイン前のIDを送り込む" },
    { label: "利用者がそのままログインする", note: "アプリがIDを作り直さない" },
    { label: "同じIDが認証済みになる", note: "攻撃者も同じIDを知っている" },
    { label: "攻撃者が本人になりすます", note: "パスワードは必要ない" },
  ]}
/>

MITREのCWE-384も、既存のセッションIDを無効にしないまま利用者を認証することを、認証済みセッションを盗まれる機会を与える弱点として挙げています。

被害は、なりすましでできることすべてに及びます。IPAは、不正送金、意図しない購入や退会、パスワードなどの設定変更、非公開情報の閲覧を例に挙げています。

## セッションIDの作り方

自分で作るより、フレームワークのセッション機能を使うのが基本です。IPAも、セッション管理機能を備えた製品を使えば、自前でIDを生成する必要はないと説明しています。使う製品の設定を確かめるときや、やむを得ず自前で作るときは、OWASPの次の基準を目安にします。

<Stats source="OWASP Session Management Cheat Sheet">
<Stat value="64ビット以上" label="セッションIDに必要なエントロピー" />
<Stat value="16文字以上" label="64ビットを16進数で表したときの長さ" />
</Stats>

- 暗号論的に安全な疑似乱数生成器（CSPRNG）で作る
- IDに利用者名や権限など、意味のある情報を入れない
- `PHPSESSID` のように技術を推測させるCookie名は、一般的な名前に変える

なお、この64ビットは文字数ではなくランダムさの量です。一部が固定の値なら、その分だけ実際のエントロピーは減ります。

## Cookieの属性を設定する

セッションIDはCookieで受け渡します。IPAは、URLパラメータに入れるとRefererから外部に漏れるおそれがあると説明しています。OWASPも、履歴やログへの漏えいに加えて固定化を容易にする点を挙げ、Cookie以外の方法で受け付けないよう勧めています。

<Figure title="セッションCookieの属性" source="OWASP Session Management Cheat Sheet、MDN「Using HTTP cookies」">

| 属性 | 働き | 設定の目安 |
| --- | --- | --- |
| `Secure` | HTTPSの通信でだけ送る | 付ける |
| `HttpOnly` | JavaScriptから読めなくする | 付ける |
| `SameSite` | クロスサイトのリクエストで送るかを制御する | `Strict` か `Lax` を明示する |
| `Domain` | 指定するとサブドメインにも送られる | 指定しない |
| `Path` | 送る対象のパスを絞る | 必要な範囲にする。安全の境界にはならない |
| `__Host-`（名前の接頭辞） | `Secure` 必須、`Domain` なし、`Path=/` を強制する | 使える環境なら使う |

</Figure>

Express（express-session）での設定例です。

```js
import session from "express-session";

app.use(
  session({
    name: "__Host-id",
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
      httpOnly: true,
      secure: true,
      sameSite: "strict",
      path: "/",
    },
  }),
);
```

ロードバランサーなどのプロキシでHTTPSを終端している場合は、Expressの `trust proxy` も設定します。設定がないと、`secure: true` のCookieが発行されません。

`SameSite=Strict` では、外部サイトのリンクから来たときにCookieが送られず、ログインしていない画面に見えることがあります。アプリの使い方に合わせて `Lax` と使い分けてください。`SameSite` はCSRF対策の補助で、トークンなどの代わりにはなりません。詳しくは[CSRFの解説](/csrf/)にまとめています。

<Note tone="caution">

`HttpOnly` はCookieの値を読まれにくくするだけです。[XSS](/xss/)があれば、攻撃者のスクリプトは本人のブラウザから操作を実行できます。XSS自体の対策も欠かせません。

</Note>

### localStorageにセッションIDを置かない

OWASPは、認証トークン、セッションID、JWT、リフレッシュトークンを `localStorage` や `sessionStorage` に保存しないよう求めています。同じオリジンで動くJavaScriptならどれでも読めるため、XSSが1件あるだけですべて漏えいするからです。代わりに、`HttpOnly`・`Secure`・`SameSite=Strict` のCookieか、BFF（Backend for Frontend）の構成を勧めています。

## ログイン時にIDを作り直す

固定化を防ぐ基本は、ログインに成功した時点で新しいIDを発行し、古いIDを無効にすることです。IPAの根本的解決、OWASP Top 10:2025のA07も同じ対応を求めています。

```js
app.post("/login", async (req, res, next) => {
  const user = await authenticate(req.body);
  if (!user) {
    return res.status(401).send("ログインできませんでした");
  }

  req.session.regenerate((regenerateError) => {
    if (regenerateError) return next(regenerateError);

    req.session.userId = user.id;
    req.session.save((saveError) => {
      if (saveError) return next(saveError);
      res.redirect("/");
    });
  });
});
```

OWASPは、ログインのほかにも、パスワードの変更、権限の変更、管理者への切り替えなど、権限が変わる場面でIDを作り直すよう求めています。アプリが発行していないIDを受け取ったときは、そのまま受け入れないようにします。

## 有効期限とログアウトをサーバー側で処理する

OWASPは、期限切れの判定をサーバー側で行うよう求めています。クライアント側だけで管理すると、値を書き換えられて期限を延ばされるおそれがあるからです。

<Figure title="セッションの期限の種類と目安" source="OWASP Session Management Cheat Sheet">

| 種類 | 内容 | 目安 |
| --- | --- | --- |
| アイドルタイムアウト | 操作がない状態が続いたら切る | 重要度の高いアプリは2〜5分、低リスクのアプリは15〜30分 |
| 絶対タイムアウト | 操作があっても、一定時間で再ログインを求める | 1日の業務で使うアプリなら4〜8時間 |
| 更新タイムアウト | 利用中に定期的にIDを作り直す | 旧IDは短い猶予の後に無効にする |

</Figure>

この数字は目安です。OWASPも、アプリとデータの重要度に応じて決めるものとしています。

ログアウトでは、次の順に処理します。

<Steps>
<Step title="サーバー側のセッションを破棄する">

ブラウザのCookieを消すだけでは足りません。盗まれた値が使えないよう、サーバー側で無効にします。

</Step>
<Step title="Cookieを削除する">

発行時と同じ属性を指定して消します。

</Step>
<Step title="機密ページをキャッシュさせない">

機密情報を含むページには `Cache-Control: no-store` を付けます。OWASPは、ログアウト時に `Clear-Site-Data` で閲覧データを消す方法も挙げています。

</Step>
</Steps>

```js
app.post("/logout", (req, res, next) => {
  req.session.destroy((destroyError) => {
    if (destroyError) return next(destroyError);

    res.clearCookie("__Host-id", {
      httpOnly: true,
      secure: true,
      sameSite: "strict",
      path: "/",
    });
    res.redirect("/login");
  });
});
```

SSOを使っている場合、OWASP Top 10:2025のA07は、関連するアプリも含めて終了させるシングルログアウトの重要性を挙げています。

## ログと監視

セッションの作成、更新、破棄、ログイン、ログアウト、権限の変更、タイムアウトを記録します。OWASPは、セッションIDそのものをログに残さず、相関を取りたいならソルト付きハッシュを使うよう勧めています。ログが漏れると、そのままなりすましに使われるおそれがあるからです。

## よくある質問

### Q. セッションハイジャックと固定化は何が違いますか？

ハイジャックは、他人のセッションを乗っ取る攻撃全体を指します。固定化はその手口の一つで、攻撃者が知っているIDのまま利用者にログインさせる方法です。IDを盗む代わりに、先にIDを決めておく点が違います。

### Q. ログインし直せば、盗まれたセッションは使えなくなりますか？

アプリによります。新しいログインで古いセッションが無効になるとは限りません。パスワード変更などの重要な操作のあとに既存のセッションを無効にする処理や、利用者が自分でセッションを切れる機能を用意しておくと安心です。

### Q. JWTを使えばセッション管理は不要ですか？

不要にはなりません。漏えいへの備え、有効期限、ログアウト時の無効化は、JWTでも考える必要があります。OWASP Top 10:2025のA07も、ログアウトや期限切れの際にセッションや認証トークンを適切に無効化するよう求めています。保存場所についても、OWASPは `localStorage` を避けるよう勧めています。

出典: [IPA「安全なウェブサイトの作り方」セッション管理の不備](https://www.ipa.go.jp/security/vuln/websecurity/session-management.html)、[OWASP Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)、[OWASP Top 10:2025 A07 Authentication Failures](https://top10.owasp.org/2025/A07_2025-Authentication_Failures/)、[MITRE CWE-384](https://cwe.mitre.org/data/definitions/384.html)、[MDN「Using HTTP cookies」](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies)、[express-session](https://expressjs.com/en/resources/middleware/session.html)
