Cookieとは
本来ステートレスなhttpアクセスをステートフルにしてくれる便利な仕組みのことです。
認証情報やショッピングカートの情報をブラウザ側で保持するために使われたりします。
Cookieという名前の由来は諸説あるようですが、ブラウザに保存される小さなデータ片のようなものだと思っておけばよいです。おしゃれな名前ですね。
どのように使われるのか
Cookieの扱いは以下で規定されています。
- RFC6265 (https://tex2e.github.io/rfc-translater/html/rfc6265.html, 日本語訳が付いているので読みやすい)
- RFC6265bis(https://www.ietf.org/archive/id/draft-ietf-httpbis-rfc6265bis-14.html, RFC6265の改訂版)
細かいことを色々すっ飛ばすと、ブラウザ視点での大まかな流れは以下になります。
- リクエストを投げる
- レスポンスにSet-Cookieヘッダが含まれていたら、値をCookieストアに保存
- 以降のリクエストでは保存済みの値をCookieヘッダに設定して送信
簡単ですね。
次はもう少し細かい仕様について見ていきましょう。
Set-Cookieヘッダの仕様について
Set-Cookieヘッダのフォーマットは以下になります。
Set-Cookie: {Cookie名}={Cookie値}; {メタデータ}; {メタデータ}; {メタデータ}; ...
Cookie名とCookie値は保存したいデータの名前と値です。
Set-Cookieヘッダの先頭に好きな名前と値をイコールで繋ぎ、セミコロンで閉じましょう。
メタデータは主にCookieの制約に関するデータです。
メタデータに指定できる属性について
Expires
有効期限(UTC時刻)を指定します。未指定の場合、ブラウザを閉じると削除されます。
例: Expires=Wed, 21 Oct 2025 07:28:00 GMT
ベストプラクティス: セッション管理に使う場合は指定しないこと1。
Max-Age
有効期間を秒単位で指定します。未指定の場合、ブラウザを閉じると削除されます。
Expires
と Max-Age
の両方が指定された場合、Max-Age
が優先されます。
例: Max-Age=3600
ベストプラクティス: Expires
と同じ。
Domain
Cookie が有効化されるドメインを指定します。デフォルトでは現在のホストが適用されます。
Cookie 名に __Host-
プレフィックスが付いている場合は指定できません(後述)。
例: Domain=example.com
ベストプラクティス: 指定しない2。
Path
Cookie が有効化されるパスを指定します。
Cookie 名に __Host-
プレフィックスが付いている場合は Path=/
を指定しなければなりません(後述)。
例: Path=/account
ベストプラクティス: できるだけ狭いパスを指定する3。
Secure
HTTPS 接続時のみ Cookie を送信する場合に指定します。
Cookie 名に __Host-
または __Secure-
プレフィックスが付いている場合は指定しなければなりません(後述)。
例: Secure
ベストプラクティス: 指定する4。
HttpOnly
JavaScript からのアクセスを禁止する場合に指定します。
例: HttpOnly
ベストプラクティス: 指定する5。
SameSite
クロスサイトリクエストでの Cookie 送信を制御する場合に指定します。
RFC6265bis で追加されました。
eTLD+1 6(.co.jpや.comなどに登録できるドメイン名)が同じならSame Site、そうでないならCross Siteです。
-
Strict
: Same SiteにだけCookieの送信を許可する -
Lax
: Cross SiteにはGETリクエストのみ許可する -
None
: Cross Siteでも制限なし
デフォルト値は Lax
です。
例: SameSite=Strict
ベストプラクティス: ユーザーアクションに関連する場合は Strict
。それ以外の場合は指定しない7。
歴史的な経緯からか、属性名にKebab-CaseとSnakeCaseが混ざっていて一貫性がないですね。
ブラウザからリクエストを送信する際には、上述したメタデータの制約を満たすCookie名とCookie値のペアをリストアップして、Cookieヘッダに詰め込みます。
Cookie名のプレフィックスについて
なんとCookie名につけたプレフィックスによってメタデータに設定できる値が制約されます。
-
__Host-{Cookie名}
: Domainは指定不可。Pathには/
を指定しなければならない。Secureも指定しなければならない。 -
__Secure-{Cookie名}
: Secureを指定しなければならない
ややこしいですね。 これにはメタデータの誤設定や攻撃者によるCookieの上書きを防ぐ効果があります。
__Host-
プレフィックスを付けられる場合は付けて、それ以外の場合は__Secure-
プレフィックスを付ける事が推奨されています8。
Q. JS側で同じような機能を実装できるんじゃないの?
A. 可能です。でもブラウザに搭載されているせっかくの便利機能なので使いましょう。JavaScriptから隔離された状態でデータを扱えるのでセキュアです。
Q. Cookieレスって聞いたことあるけど、そのうちCookieの知識は不要になる?
A. なりません。紛らわしいですが、CookieレスとはブラウザによるサードパーティCookie(Cross Siteに送信されるCookie)の制限や廃止の動きを指します。
Web広告業界ではCookieに頼らない実装方式への転換が求められているという背景があるため、Cookieレスという言葉が使われているようです。
ファーストパーティCookie(Same Siteに送信されるCookie)は今後も使われ続けるでしょう。
(おまけ) Cookieの実体
Windows版のChromeを例に挙げると、C:\Users\{ユーザー名}\AppData\Local\Google\Chrome\User Data\Default\Cookie
にsqliteファイルとしてCookieのデータが保存されています。
sqlite3コマンドなどで普通に開けます。
ブラウザ側で保持する情報は仕様で定められていますが、カラム名や保存形式に関する指定は無いため、ブラウザごとに自由に実装されているようです。
例えばSQLiteテーブルのカラム名はブラウザごとに異なっていますし、ChromeだとCookie値は暗号化されていますが、FireFoxでは平文のままだったりします。不思議ですね。
-
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#expire-and-max-age-attributes ↩
-
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#domain-and-path-attributes ↩
-
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#domain-and-path-attributes ↩
-
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#secure-attribute ↩