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属性を設定した場合にどうなるかの一覧である。

設定値

効力

備考

なし

www.example.comのみ

domain属性を指定しなかった場合は、そのページのドメインのみに送信される。

www.example.com

www.example.comそのサブドメイン

  • hoge.www.example.com

  • fuga.www.example.com

  • …など

設定しなかった場合と効力が異なる(設定した方が範囲が広がってしまう)ので注意。

example.com

example.comそのサブドメイン

  • www.example.com

  • hoge.example.com

  • hoge.fuga.example.com

  • …など

google.com

無効

自身のドメイン(www.example.com)を含む範囲でなければならない。

hoge.www.example.com

無効

com

無効

自身のドメインを含む範囲であっても、comco.jpなどの広大な範囲を指定することはできない。

  • ドメインの先頭に.を付けても構わない。例えば、「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へのページ遷移

サイトA上にあるサイトBへのPOST送信の<form>フォーム

サイトA上での<img><script>によるサイトBのリソース読み込み

サイトA上での<iframe>によるサイトBのページ読み込み

サイトAからのXMLHttpRequestによるサイトBへのAjax

  • ※: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年

Netscapeによる最初の仕様

HTTPヘッダによる設定と参照、domain、path、expires、secureの各属性が定められている。曖昧な点や未定義な点が多い仕様で、しかも現在原文が残っていないらしいが、今でもおおむねこれがベースとなっている。

1997年

RFC 2109

新たにversion属性を必須とするなど、Netscapeの仕様に非互換な仕様を加えたため、全く普及せず後に廃止。ただし、このとき考案されたmax-age属性などは現在採用されている。

2000年

RFC 2965

ヘッダ名をSet-Cookie2とするなど、再び大胆な変更を加えようとしたため、全く普及せず後に廃止。

2011年

RFC 6265

現実世界での利用状況から逸脱しないようにして定められた最も新しい仕様。日付の書式などがわずかに異なってはいるものの、本来のNetscape版に近い仕様となっている。max-age属性が再び定められ、httponly属性もここで登場した。

2016年

samesite属性に関する新しい仕様

セキュリティを高めることを目的として、新たに考案されたsamesite属性に関する仕様。

外部リンク