Remember me は通常セッションの延長ではない
Remember me は、「ブラウザを閉じてもログイン状態を長く保つ」機能です。
重要なのは、通常の短命セッションを無限に伸ばすのではなく、長期ログイン用の別トークンとして設計することです。
通常セッション:
短命
操作中のログイン状態を表す
サーバー側セッションストアで管理する
Remember me:
長命
新しいセッションを再発行するための入口
端末単位で管理する
盗難時の失効と検知を考える
同じ session_id を30日や90日伸ばすだけだと、盗まれたときの影響範囲が大きくなります。
基本フロー
ログイン時に「ログイン状態を保持する」を選んだ場合、2種類のCookieを発行します。
Set-Cookie: session_id=short_session; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=7200
Set-Cookie: remember_token=long_token; Path=/auth/remember; HttpOnly; Secure; SameSite=Lax; Max-Age=2592000
役割:
| Cookie | 役割 | 期限 |
|---|---|---|
session_id | 通常のログイン状態 | 短い |
remember_token | セッション再発行用 | 長い |
通常の画面アクセスでは session_id を使います。session_id が切れていて、remember_token が有効な場合だけ、新しい session_id を発行します。
session_id 有効
-> そのままログイン済み
session_id 期限切れ / なし
remember_token 有効
-> remember token を検証
-> 新しい session_id を発行
-> remember token もローテーション
DBにはハッシュだけ保存する
Remember token は、パスワードに近い秘密値です。DBには平文で保存しません。
発行する値:
raw_token = ランダムな長い文字列
token_hash = hash(raw_token)
DBに保存:
CREATE TABLE remember_tokens (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
token_hash TEXT NOT NULL UNIQUE,
device_label TEXT,
user_agent_hash TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
last_used_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ
);
Cookieに入れるのは raw_token、DBに残すのは token_hash です。DBが漏れても、そのままCookieとして使えない状態にします。
ローテーションする
長期トークンは、使うたびに入れ替えます。
1. Cookieのremember_tokenを受け取る
2. hashしてDBを検索する
3. 有効期限とrevoked_atを確認する
4. 新しいremember_tokenを発行する
5. 古いtokenをrevokedにする
6. 新しいsession_idを発行する
これにより、古いトークンを盗まれても、次回利用時に検知しやすくなります。
怪しい例:
古いremember_tokenが、すでにローテーション済みなのに再利用された
この場合、盗難や二重利用の可能性があります。対象ユーザーのRemember tokenを全失効し、再ログインを求める判断ができます。
端末単位で管理する
Remember me は端末単位で扱うのが自然です。
管理画面では、次のような表示ができます。
| 項目 | 例 |
|---|---|
| 端末名 | Chrome on macOS |
| 最終利用 | 2026-06-27 10:30 |
| 作成日時 | 2026-06-01 09:00 |
| IPの目安 | Tokyo, JP |
| 操作 | この端末をログアウト |
端末単位にしておくと、「この端末だけログアウト」「全端末ログアウト」「見覚えのない端末を削除」が実装しやすくなります。
Path を狭くする
Remember token は、通常のAPIや画面アクセスに毎回送る必要がありません。
Set-Cookie: remember_token=...; Path=/auth/remember; HttpOnly; Secure; SameSite=Lax
Path=/auth/remember のように狭くすると、通常の /api/orders や /dashboard には送られません。漏洩面を少し小さくできます。
ただし、実装が複雑になる場合は、まず正しい失効・ローテーション・HttpOnly・Secureを優先します。
盗難時に何が起きるか
Remember token が盗まれると、攻撃者は新しいセッションを作れる可能性があります。
対策:
- tokenは長くランダムにする
- DBにはハッシュだけ保存する
- 使用時にローテーションする
- 再利用を検知する
- 端末単位で失効できるようにする
- パスワード変更時に全Remember tokenを失効する
- 重要操作では再認証を求める
Remember me は便利ですが、長期の認証入口を増やす機能でもあります。管理画面、決済、個人情報変更では、Remember meで復帰しただけの状態から追加確認を入れる設計もあります。
通常セッションとの違い
| 観点 | 通常セッション | Remember token |
|---|---|---|
| 目的 | 操作中のログイン状態 | セッション再発行 |
| 期限 | 短い | 長い |
| 送信頻度 | 多い | 必要なときだけが望ましい |
| 失効単位 | セッション | 端末 |
| 盗難時の影響 | 期限まで操作可能 | 新しいセッションを作られる可能性 |
Remember token を「長いsession_id」として扱わないことが大事です。
実装チェックリスト
- 通常セッションとRemember tokenを分けている
- Remember tokenは十分に長いランダム値
- DBにはハッシュだけ保存している
- 使用時にトークンをローテーションしている
- 古いトークンの再利用を検知できる
- 端末単位で失効できる
- パスワード変更時に全失効できる
HttpOnly/Secure/SameSiteを設定している- 重要操作では再認証を検討している
まとめ
Remember me は便利な機能ですが、認証の長期入口です。
通常セッションを長くするのではなく、長期トークンで新しい短命セッションを再発行する設計にすると、安全性と使いやすさのバランスを取りやすくなります。