Takeo

Takeo

この記事の目次

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-AgeExpires
指定方法相対時間(秒)絶対日時(HTTP日時)
例Max-Age=3600Expires=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アプリで次を試す。

  1. Chrome DevToolsの Network タブを開く。
  2. ログインなどのレスポンスから Set-Cookie を探す。
  3. Application → Storage → Cookies でCookieの名前・値・有効期限を確認する。
  4. Max-Age=10など短い寿命のCookieを設定し、期限内と期限後のリクエストを比較する。
  5. 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を安全に扱うためのセキュリティ設計を解説する。

参考資料