Cookie の仕様とセキュリティ

このエントリーをはてなブックマークに追加

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

Set-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

Cookie を参照する

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

Cookie: name=0=value0; name1=value1

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

クッキーの順序は以下のように決まります。

また後述するように、クッキーは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つサーバーに送るようになります。

JavaScript を使って Cookie を保存・参照する

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

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 を読んだ時に得られる値も変化しません。

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

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番号

Cookie が絡むセキュリティ関係の問題

このエントリーをはてなブックマークに追加
Home