Cookie・セッション管理シリーズ 第2回 / 全5回
有効期限付きCookieはどう動くのか? ExpiresとMax-Ageの仕組み
Webサイトで「30日間ログイン状態を保持する」と表示されることがある。この30日間という期限は、どこに保存され、誰が判定しているのだろうか?
この記事では、ブラウザに保存されるCookieの有効期限を中心に、HTTPヘッダーとアーキテクチャ図で仕組みを確認する。第1回で紹介した、CookieにセッションIDを保存するWebアプリケーションを例にする。
この記事ではCookieの保存・送信期限と、サーバー側の認証セッション期限を区別する。Cookieの期限が切れることと、サーバー上のセッション情報が削除されることは同義ではない。
1. 有効期限はどこで管理されるのか
CookieはWebサーバーがSet-Cookieレスポンスヘッダーでブラウザに設定を指示し、ブラウザが保存・送信を管理する。サーバーが毎回Cookieの残り時間を確認して送信を止めるわけではない。
この図では、ブラウザがCookieの期限を管理し、Webサーバーが受け取ったセッションIDを使ってセッションストアを照会する。両者の有効期限は独立している。
2. Max-Age:発行時点からの相対的な期限
Copied!!HTTP/1.1 200 OK Set-Cookie: session_id=abc123; Max-Age=3600; Path=/; Secure; HttpOnly
Max-Age=3600は、Cookieを受信した時点から**3600秒(1時間)**の寿命を指定する。単位は秒。期限内で、Domain・Path・Secure・SameSiteなどの送信条件を満たすリクエストでは、ブラウザがCookieを送信する。
ここでの401 Unauthorizedは一例であり、実際にはログイン画面へのリダイレクトなど、アプリケーションによって挙動が異なる。
3. Expires:絶対日時で期限を指定する
Copied!!Set-Cookie: session_id=abc123; Expires=Wed, 18 Nov 2026 12:00:00 GMT; Path=/; Secure; HttpOnly
ExpiresはHTTP日時形式で特定の日時を指定する。GMTで表現される点に注意。ブラウザは期限が過ぎたCookieをリクエストに付けなくなる。
| 属性 | Max-Age | Expires |
|---|---|---|
| 指定方法 | 相対時間(秒) | 絶対日時(HTTP日時) |
| 例 | Max-Age=3600 | Expires=Wed, 18 Nov 2026 12:00:00 GMT |
| 基準 | Cookieを受信した時点 | 指定された期限日時 |
| 両方指定された場合 | こちらが優先 | 無視される |
ブラウザの時刻とサーバーの時刻にずれがある場合、Expiresの取り扱いには実装上の補正が入ることもある。一般的な有効期間の指定には、相対時間で書けるMax-Ageが扱いやすい。
両方指定したらどうなる?
Copied!!Set-Cookie: session_id=abc123; Max-Age=3600; Expires=Wed, 18 Nov 2026 12:00:00 GMT
この場合、Max-Age=3600が優先される。互換性のため両方を設定する実装もあるが、矛盾する期限を指定しないほうが読みやすい。
4. 期限切れになったCookieはどうなる?
重要なのは、期限切れCookieはブラウザから送信されなくなるという点。ブラウザ内部での物理的な削除処理がいつ走るかをアプリケーションが制御する必要はない。
なお、Max-Ageの期限はCookieを受信してからの寿命であり、リクエストのたびに自動延長されるわけではない。延長したい場合、サーバーが新たなSet-Cookieを返すなどの仕組みが必要になる。
5. ブラウザを閉じるとCookieは消える?
Max-AgeもExpiresも指定しないCookieは、一般にセッションCookieと呼ばれる。
Copied!!Set-Cookie: session_id=abc123; Path=/; Secure; HttpOnly
セッションCookieはブラウザセッションの終了時に削除されることを想定している。ただし、ブラウザのセッション復元機能によって、ブラウザを再起動しても復元される場合がある。「ブラウザを閉じれば必ずログアウトする」とは設計しないほうがよい。
一方、Max-AgeやExpiresを持つCookieは永続Cookieと呼ばれ、ブラウザを終了しても期限内なら保持され得る。ただし、ユーザーの手動削除やブラウザのプライバシー設定などで早く消える場合もある。
6. Cookieの期限とサーバー側セッションの期限は別物
ログイン状態の維持には、Cookieだけでなくサーバー側のセッションストアが関わることが多い。
この例では、Cookieが1時間残っていても、サーバー側のセッションが30分で失効するため、30分後には認証できなくなる。
| 状態 | ブラウザのCookie | サーバー側セッション | 結果(例) |
|---|---|---|---|
| 発行後10分 | 有効 | 有効 | 認証成功 |
| 発行後40分 | 有効 | 期限切れ | 認証失敗 |
| 発行後70分 | 期限切れ | 期限切れ | Cookieを送らず認証失敗 |
逆に、Cookieが先に期限切れになっても、サーバー側のセッション情報が残る場合がある。Cookieの失効は、サーバー側データの自動削除を意味しない。
「30日間ログイン」を実現するには?
Cookieを30日間保存するだけでは不十分。サーバー側の認証セッションやリフレッシュトークンなども、必要な期限・失効方法を設計する必要がある。単純にすべてを30日間有効にするのではなく、盗難時のリスクも考慮する。
7. ログアウト時にCookieを削除する方法
サーバーから、同じ名前・Path・Domainに対応するCookieを期限切れにする指示を返す。
Copied!!HTTP/1.1 200 OK Set-Cookie: session_id=; Max-Age=0; Path=/; Secure; HttpOnly
Max-Age=0(または負の値)はCookieを即座に失効させる。削除対象を正しく指定するには、元のCookieと名前・Path・Domainを合わせる必要がある。HttpOnlyのCookieでも、サーバーのSet-Cookieによって失効させられる。
ただし、安全なログアウトにはサーバー側セッションも無効化することが重要。Cookieを削除しただけでは、盗まれたセッションIDがサーバーでまだ有効な場合、再利用されるおそれがある。
8. Chrome DevToolsで実際に確認する
自分で動作を確認するなら、テスト用のWebアプリで次を試す。
- Chrome DevToolsの Network タブを開く。
- ログインなどのレスポンスから
Set-Cookieを探す。 - Application → Storage → Cookies でCookieの名前・値・有効期限を確認する。
Max-Age=10など短い寿命のCookieを設定し、期限内と期限後のリクエストを比較する。- Network → Request Headers の
Cookieヘッダーを確認する。
開発時の確認用レスポンス例:
Copied!!Set-Cookie: demo=hello; Max-Age=10; Path=/; SameSite=Lax
10秒以内は送信条件を満たせばdemo=helloが送られ、期限後は送られなくなる。なお、Secureを指定したCookieは原則HTTPS接続で扱う(localhostにはブラウザによる例外がある)。
9. まとめ
Max-Ageは相対時間(秒)、Expiresは絶対日時を指定する。- 両方指定した場合は**
Max-Ageが優先**される。 - Cookieの保存・送信期限はブラウザ側が管理する。
- セッションCookieはブラウザ再起動後も復元される場合がある。
- Cookieの期限とサーバー側セッションの期限は独立している。
- ログアウトではCookieの失効に加えて、サーバー側セッションも無効化する。
次回はSecure、HttpOnly、SameSiteを中心に、Cookieを安全に扱うためのセキュリティ設計を解説する。
