Cookieの仕様
2020/02/23更新
目次
概要
HTTP cookieは、歴史が長くて、仕様が古めかしかったり曖昧だったりする部分が多く、さらに近年は個人情報問題などで再び注目されて新たな属性などが追加されている。ここではそのようなCookieの仕様が現在どうなっているのか、調べてまとめることにする。
「Cookieとは何か」という初歩的・概念的な話や、実際の使用例などについては、このページでは解説しない。
Cookieの設定方法
HTTPヘッダによる設定
Cookieは、基本的にはページリクエスト時に、サーバーから以下のようなレスポンスヘッダをつけて返すことで設定する。
Set-Cookie: name=value; attr1=value1; attr2=value2; …
名前「
name
」に値「value
」を設定する。この部分のみ必須。名前には、以下の文字と半角スペースを除く半角英数字が使用できる。
( ) < > @ , ; : \ " / [ ] ? = { }
値には、以下の文字と半角スペースを除く半角英数字が使用できる。また、ダブルクォートで囲ってもよい。
, ; \ "
名前または値に、使用できない記号や日本語等が含まれる場合は、何らかのエンコード(通常URLエンコードが使われる)が必要となる。
ダブルクォートで囲っていない値に
=
を含むことは許される。その場合、最初の=
が名前と値の境と見なされる。単純に=
で分割して配列化するような処理をしている場合は注意が必要となる。後述の属性を設定するには、「
;
」(セミコロン+スペース)で区切って、並べていく(末尾にセミコロンは付けない)。複数の名前を設定するには、Set-Cookieヘッダを複数送信する。
JavaScriptによる設定
JavaScriptでは、document.cookie
に値を設定することで、Cookieを設定できる。
document.cookie = 'name=value; attr1=value1; attr2=value2; …';
document.cookie
に渡す値は、Set-Cookieヘッダと同じ書式の文字列である。複数の名前を設定するには、
document.cookie
への代入文を複数回記述する。この構文は、単なるプロパティへの文字列代入ではないことに注意されたい。
document.cookie
は、セッターおよびゲッターとして機能するアクセサープロパティである。
HTMLによる設定
HTMLでは、<meta http-equiv="~">
というHTTPヘッダを返した場合と同様の効果が得られるタグがあるが、これを使ってCookieを設定する方法は現在では廃止され、最新のブラウザ(Chrome 65以降、Firefox 68以降、など)でも使用できなくなっている。→ 参考:<meta>: 文書レベルメタデータ要素 - HTML: HyperText Markup Language | MDN
<html> <head> <!-- この方法は現在では不可 --> <meta http-equiv="Set-Cookie" content="name=value; ~"> ...
Cookieの参照方法
HTTPヘッダによる参照
Cookieはブラウザからリクエストヘッダによって送られてくるので、サーバー側ではこれを参照することで取得できる。
Cookie: nameA=valueA; nameB=valueB; …
「
name=value
」の部分のみが、「;
」(セミコロン+スペース)で区切られて送られる(末尾にセミコロンは付かない)。どのCookieが送られてくるかは、それぞれの属性や状況によって決定される。ただ、設定時の属性を参照することはできない。
名前が同じでも、後述のdomain属性やpath属性が異なると別のCookieとして扱われるため、同じ名前のCookieが複数送られることもありえる。
CGIでは、環境変数
HTTP_COOKIE
に送られてきたCookieの内容がセットされる。
JavaScriptによる参照
JavaScriptでは、document.cookie
を参照することで、Cookieを取得できる。
console.log(document.cookie); // 'nameA=valueA; nameB=valueB; …'
document.cookie
を参照すると、Cookieヘッダで送られるのと同じ書式の文字列が得られる。document.cookie
はアクセサプロパティであるため、得られる文字列は設定時に代入したものとは異なるので注意が必要である。
Cookieの属性
domain属性
そのCookieを送信するドメインの範囲を指定できる。
Set-Cookie: name=value; domain=www.example.com
以下は、例としてwww.example.com
のページでdomain属性を設定した場合にどうなるかの一覧である。
設定値 | 効力 | 備考 |
---|---|---|
なし | | domain属性を指定しなかった場合は、そのページのドメインのみに送信される。 |
|
| 設定しなかった場合と効力が異なる(設定した方が範囲が広がってしまう)ので注意。 |
|
| |
| 無効 | 自身のドメイン( |
| 無効 | |
| 無効 | 自身のドメインを含む範囲であっても、 |
ドメインの先頭に
.
を付けても構わない。例えば、「example.com
」は「.example.com
」としても問題ない。
path属性
そのCookieを送信するパスの範囲を指定できる。
Set-Cookie: name=value; path=/hoge/
path属性を指定すると、そのパスとサブディレクトリ以下のパスに対してそのCookieが送信される。
末尾に
/
を付けない場合、ブラウザによって挙動が異なる。単純な文字列の前方一致でマッチングを行なうブラウザでは、「/hoge
」に対して「/hogefuga
」がマッチしてしまったりするので注意が必要である。→ 参考:ブラウザごとの cookie path の挙動の違い何も指定しない場合、そのページのあるディレクトリパスを指定したのと同じこととなる。
ドメイン内の全てのパスに送信させるには、「
path=/
」とする。
expires属性
そのCookieの有効期限を指定できる。
Set-Cookie: name=value; expires=Tue, 01 Jan 2030 00:00:00 GMT
時刻の書式が上記の通り「
Wdy, DD Mon YYYY HH:MM:SS GMT
」と定められているので注意が必要である。年月日の間はハイフンが使われて「
Wdy, DD-Mon-YYYY HH:MM:SS GMT
」となっている場合もある。これはNetscapeが最初に定めた仕様で、古い文献ではこの書式で説明されていることが多い。スペースの方はHTTPヘッダに合わせてRFCで定められた書式で、現在のブラウザではいずれも有効と思われるが、スペースの方が一般的のようである。過去の時刻を指定すると、そのCookieは削除される。
無期限という指定はできない。遠い未来の日付を指定すれば、事実上ほぼ無期限にすることはできる。2038年問題が懸念されるためなのか、2030年頃の日付を指定することが多い。
後述のmax-age属性と同時に指定された場合は、max-age属性が優先され、expires属性は無効となる。最近はmax-age属性の方が使われることが多い。
expires属性、max-age属性ともに指定がない場合は、ブラウザ終了時が有効期限となる(ただし、最近のブラウザでは、一度ブラウザを終了して削除されたとしても、セッション復元機能などによって復元される場合がある)。
max-age属性
そのCookieの有効期限を指定できる。前述のexpires属性と同じ目的のものであるが、こちらの方が後から作られた。
Set-Cookie: name=value; max-age=86400
Cookieが有効な期間を現在からの秒数で指定する。無期限という指定はできない。
0
を指定すると、そのCookieは削除される。新しい属性のため、古いブラウザではサポートされていない。
前述の通り、expires属性と同時に指定された場合は、max-age属性が優先される。
secure属性
Cookieの送信をhttpsの場合に限定できる。secure属性には値は無い。
Set-Cookie: name=value; secure
secure属性が無い場合、http/httpsのどちらで設定されたCookieも、http/httpsのどちらにも送信されてしまう。
最近のブラウザ(Chrome 52以降、Firefox 52以降、など)では、httpのページでsecure属性を付けたCookieを発行することはできなくなった。
httponly属性
CookieがJavaScriptから参照されるのを無効にすることができる。httponly属性には値は無い。
Set-Cookie: name=value; httponly
httponly属性が付いたCookieは、JavaScriptの
document.cookie
でアクセスすることが一切できなくなる。名前からsecure属性の反対の意味を連想してしまいがちであるが、そうではないので勘違いしないよう注意されたい。
samesite属性
Cookieがクロスサイトのリクエストで送信されるのを制限できる。2020年現在、まだ実験段階の新しい属性であるが、ブラウザ側の実装は進んでおり、理解や対策が必要な属性となっている。
Set-Cookie: name=value; samesite=lax
samesite属性は以下の3種類の値のいずれかを取る。
値 | 意味 |
---|---|
strict | 表示中のドメインとは異なるドメインへのリクエストでは、常にCookieを送信しない。 |
lax | 表示中のドメインとは異なるドメインへのリクエストのうち、通常のリンクによるページ遷移のように、ブラウザに表示されるURLが変化するようなリクエスト(top-level navigation)の場合のみCookieを送信する。 |
none | 従来通り、表示中のドメインとは異なるドメインへのリクエストでも、常にCookieを送信する。 |
以下は、主なクロスリクエストにおけるCookieの送信が、上記の各値のときにどうなるかを表にしたものである。
クロスリクエストの種類 | strict | lax | none |
---|---|---|---|
サイトAから |
|
|
|
サイトA上にあるサイトBへのPOST送信の |
|
|
|
サイトA上での |
|
|
|
サイトA上での |
|
|
|
サイトAからの |
|
| ※ |
※:AjaxにおけるクロスオリジンのCookie送信では、
samesite=none
はあくまで条件の一つであり、他にAccess-Control-Allow-Origin
ヘッダとAccess-Control-Allow-Credentials
ヘッダが必要で、さらにJavaScript側でもxhr.withCredentials = true;
の指定が必要である。
Chrome 80以降では、samesite属性の設定が無い場合、従来通りとなるnone
ではなく、従来と比べて大きく挙動が異なるlax
が指定されたものと見なされるので注意が必要である。さらに、none
を指定する場合は、同時にsecure属性も必ず付けなければいけないことになっている。
属性名の大文字小文字の区別
属性名は、大文字と小文字の区別は無い。全て小文字(domain、path、expires、max-age、secure、httponly、samesite)とするか、またはアッパーキャメルケース(Domain、Path、Expires、Max-Age、Secure、HttpOnly、SameSite)で書かれることが多い。
Cookieの仕様の歴史
CookieはNetscapeによって初めて提案され、現在ではRFCで定義されたものに基づいて各ブラウザが実装している。
年 | 仕様 | 内容 |
---|---|---|
1994年 | HTTPヘッダによる設定と参照、domain、path、expires、secureの各属性が定められている。曖昧な点や未定義な点が多い仕様で、しかも現在原文が残っていないらしいが、今でもおおむねこれがベースとなっている。 | |
1997年 | 新たにversion属性を必須とするなど、Netscapeの仕様に非互換な仕様を加えたため、全く普及せず後に廃止。ただし、このとき考案されたmax-age属性などは現在採用されている。 | |
2000年 | ヘッダ名をSet-Cookie2とするなど、再び大胆な変更を加えようとしたため、全く普及せず後に廃止。 | |
2011年 | 現実世界での利用状況から逸脱しないようにして定められた最も新しい仕様。日付の書式などがわずかに異なってはいるものの、本来のNetscape版に近い仕様となっている。max-age属性が再び定められ、httponly属性もここで登場した。 | |
2016年 | セキュリティを高めることを目的として、新たに考案されたsamesite属性に関する仕様。 |