Cookie の仕様とセキュリティ

このドキュメントの目的は Cookie とは何かを一から説明することではないので、そもそも Cookie とは何で何に使えるのかといった話はWikipedia の Cookie の記事などを参考にして下さい。 ここでは Cookie がどういうものかは大体理解しているという前提で、仕様の確認をしていきます。

目次

Cookie を設定する一番基本的な方法は HTTP ヘッダ の Set-Cookie を使う方法です。

Set-Cookie: name=value

のような HTTP header をサーバから返すと name と value のペアがブラウザに保存されて、後からそれを参照することができます。 Set-Cookie に属性をつけて保存期間や Cookie が送信される条件などを制御することも可能です。 属性をつけるには、 " ;max-age=3600"" ;Secure" のように "; " + 属性名 + "=" + 属性の値を後ろに追加します。 (厳密には ; の後ろには半角スペースが必要で末尾には ; は付けません。多くのブラウザは半角スペースを削除したり末尾に不要な ; をつけても問題なく動くでしょうが)

Set-Cookie: name=value; max-age=3600; Secure

これは、name=value というクッキーを 3600 秒間保存しておきなさい、ただしそのクッキーが利用できるのは https のページでのみです、 と指定してることになります。

複数の name-value のペアを設定したい場合は Set-Cookie ヘッダを複数送ります。

Set-Cookie: name0=value0
Set-Cookie: name1=value1

Set-Cookie で保存された Cookie は、HTTP Request の Cookie ヘッダとしてブラウザからサーバーに送信されます。 Cookie ヘッダは

Cookie: name=0=value0; name1=value1

のように、ブラウザに保存されているクッキーの name=value のペアを "; " で連結したものものになります。 どのクッキーがサーバーに対して送信されるかは、Set-Cookie で指定した max-age や Secure などの属性によって制御することができます。 Secure が指定されていれば、サーバーが https の時にしか送信されないし、 max-age を超えた古くなったクッキーも送信されません(ブラウザから削除されます)。

Cookie ヘッダでブラウザから送信されるクッキーの順序は以下のように決まります。

  • 後述する path 属性のなるべく長いものが前に来る
  • path 属性の長さが同じ場合は、最近作られたものが前に来る

また後述するように、クッキーは name が同一でも domain, path 属性の値が異なれば別のものとして扱われるので、同じ name のクッキーが複数 Cookie ヘッダの中に現れることがありうるので注意してください。例えば、www.example.com にあるサーバーが

Set-Cookie: myname=value0; example.com; path=/
Set-Cookie: myname=value1; www.example.com; path=/

という Set-Cookie でクッキーを設定した場合、ブラウザは

Set-Cookie: myname=value1; myname=value0

のように同じ名前の Cookie を2つサーバーに送るようになります。

document.cookie というプロパティを利用して JavaScript からクッキーを設定したり参照することができます。

document.cookie = "name=value";

のようにdocument.cookieに対して文字列を代入すると、Set-Cookkie: name=valueヘッダをサーバーからブラウザに送信した場合と同じことが起こります。Set-Cookie ヘッダとどうように、属性を付けることができます。

document.cookie = "name=value; max-age=3600; Secure";

復数のクッキーを指定した場合は、Set-Cookie ヘッダと似たような感じに 1 つずつ代入します。

document.cookie = "name0=value0";
document.cookie = "name1=value1";

クッキーの値を参照するには、 document.cookie プロパティを参照します。document.cookie プロパティは参照すると Cookieヘッダで送信されるのと同じ文字列を得ることができます。

console.log(document.cookie); // “name=0=value0; name1=value1”

document.cookie は一見すると string 型のプロパティのように見えますが、そうではないことに注意して下さい。document.cookie へ代入した文字列と document.cookieを読んだ時に得られる文字列はまったく異なります。また、document.cookieに空文字を代入しても 空の Set-Cookieを送ったのと同じことにしかならないので何も起こりません。クッキーは削除されず、document.cookieを読んだ時に得られる値も変化しません。

domain 属性

Set-Cookie でクッキーをブラウザに保存する際domainという属性を付加することでクッキーが送信される、あるいはdocument.cookieでクッキーが読み取れる、ドメインを制御することができます。

Set-Cookie: name=value; domain=example.com

domain 属性が指定されている場合、そのクッキーは domain で指定された domain 自体とそのサブドメインに対して送信されます。 上の例の場合、このクッキーは example.com, www.example.com, docs.example.com などのホストに対して送信されます。 一方で domain を指定しない場合は、Set-Cookie を送信したホストにのみクッキーは送信されます。 domain属性なしで、example.com によって設定されたクッキーは www.example.com や docs.example.com には送信されません。 domainを省略した場合と、domain に今接続しているホスト名を指定した場合ではクッキーが送信される範囲が異なる点に注意が必要です。 サブドメインに送信されてはならないクッキーには domain 属性はつけてはなりません。

また domain 属性で指定するドメインは現在のホスト名を含むドメインでなくてはなりません。 そうでない値を指定した場合は無視されます。例えばあるページが www.example.com にある場合、domain に example.com を指定してクッキーが example.com 以下のあらゆるホストに対して送信されるように設定できますが、 domain に google.com を指定して google.com に対してクッキーを送信するように設定することはできません。また、domain 属性に abc.www.example.com を指定してサブドメイン abc.www.example.com にのみクッキーが送信されるようにすることもできません。

domain 属性の値の先頭に “.” を付けても構いません。その “.” は無視されます。 また念の為述べておくと domain に www.example あるいは www.example. などと指定しても www.example.co.jp と example.com にクッキーを送信されたりはしません。

path 属性

クッキーには path 属性を指定することができます。

Set-Cookie: name=value; path=/mydir

のように path 属性を指定するとクッキーは /mydir/ に含まれる URL (e.g. http://example.com/mydir/, http://example.com/mydir/index.html, http://example.com/mydir/subdir/) にのみ送信されます。path が省略された場合は現在の URL の path が使われます。例えば現在のページが http://example.com/mydir/subdir/index.html であれば /mydir/subdir/ が path に設定されます。ほとんどの場合、同一ドメインの全てのリクエストでクッキーが送信されるようにしたいと思うので、多くの場合 path=/ を常に指定することになります。path=/ を指定するのをうっかり忘れると、http://example.com/2014/11/ で指定されたクッキーが http://example.com/2013/12/ には送信されません。

さて、path も domain と同じようにクッキーが送信される範囲を制御するので、セキュリティ上重要なように一見すると思えますが、実は path はセキュリティ保護には利用できません。IPA の第 4 章 セッション対策 には path をなるべく限定しておいたほうがよいような記述がありますが、path を限定してもその他の path にあるリソースからクッキーを読む方法は存在するので気をつけて下さい。セッション ID などを保存するのであれば、普通は path=/ を指定すると思います。

max-age と expire

max-age あるいは expire 属性でクッキーの寿命が指定できます。

Set-Cookie: name=value; max-age=3600
Set-Cookie: name=value; expires=Tue, 19 Jan 2038 03:14:07 GMT
  • max-age ではクッキーの寿命を秒数で指定します。負の値を指定すると、最も過去の日付を指定したことになります。
  • expires では有効期限が切れる日付・時刻を指定します。
  • max-ageexpires の両方が指定された場合は max-age が使用されます。
  • max-age はかなり古いブラウザではサポートされない場合があります。
  • max-age, expires がなく寿命が指定されていない場合は、クッキーはブラウザが閉じられると削除されます。

secure

うっかり忘れられがちですが、セキュリティ上とても大切な仕様です。 Secure 属性をつけた場合、そのクッキーは接続が https で保護されている場合のみに送信されます。Secure 属性には値は必要ありません。

デフォルトではクッキーは接続が https なのか http なのかには関係なく動作します。 https 接続で設定されたクッキーであっても Secure 属性がなければ同じホスト名に http で接続した場合にもそのクッキーは送信されてしまい、通信経路上にいる第三者に盗聴される可能性があります。 セッション ID のような第三者に盗み見られてはならないクッキーは必ず Secure 属性をつけなくてはなりません。 絶対に忘れないようにしましょう。

httponly

httponly 属性をつけると、そのクッキーは Cookieヘッダ以外から読み取ることができなくなりなり、JavaScript から参照できなくなります。 Secure の反対の意味、 http でしか送信されない Cookie という意味では ない ので気をつけて下さい。

このオプションは XSS 脆弱性があった場合の被害を小さくします。 XSS 脆弱性によって攻撃者が任意の JavaScript が実行できてしまうと、 document.cookie の値を読んで Session ID などのログイン情報などを盗み見れてしまう可能性がありますが、 HttpOnly 属性をつけておくとクッキーが XSS 脆弱性によって読み取られることがなくなります。 Session ID などのように JavaScript から読み取る必要がないクッキーには HttpOnly を忘れずに付けておいたほうが良いでしょう。

その他

クッキーと port 番号

通信路上でのクッキーの漏洩

クッキーにセッション ID のような機密情報が含まれる場合、当然ですがクッキーはhttpsを介して行われなければなりません。

クロスサイトスクリプティング (Cross Site Scripting, XSS)

Web アプリケーションでもっともよく問題になるクロスサイトスクリプティングは端的に言えば、 ユーザの入力を HTML に変換する際のバグにより悪意のある JavaScript が実行されてしまう問題です。クッキーの処理自体が XSS 脆弱性を引き起こす原因になることはあまりないでしょう。

しかしクッキーの設定によって XSS の脆弱性があった場合の被害を緩和することは可能です。

最終更新: 2016/3/16