HTTP Cookies
Cookieとは?
Cookieとは、CGIスクリプトのようなサーバ側がクライアント側で情報を貯めたり回収したりできる総合的な機能です。単純で持続性を持ったクライアント側の情報を加えることで、WWWのクライアント・サーバ・アプリケーションは驚くほど限界が広がります。
概要
サーバはHTTPオブジェクトをクライアントへ返す時、クライアント側で貯めておく情報を送ることが可能です。その情報の対象は、URLの有効範囲に関する詳細などが含まれます。将来のクライアントからのあらゆるHTTPリクエストは、いまクライアントがサーバへ返すステートオブジェクトを含む範囲に収まります。名前の由来はわかりませんが、cookieとはそのステートオブジェクトのことです。この単純な機能が、WWWの世界で新しいタイプのアプリケーションを実現させる強力なツールをホストたちへ提供しました。ショッピング関連のアプリケーションは現在どのような商品が選択されているかの情報を蓄え、購入者はわざわざユーザIDを入力しなくても支払に関する情報が返せます。そして、1人1人の顧客情報はサイトへ蓄積され、同じ顧客が訪れた場合、クライアント側は毎回その情報を引き出すことが可能です。
詳細
cookieはHTTPレスポンスの一部としてSet-Cookieヘッダを含むことでクライアントへ渡され、CGIスクリプトを用いるのが典型的なやり方です。
HTTPレスポンスヘッダのシンタックス(Set-Cookie)
これは、今後のためにクライアント側で貯めておく新しい情報をHTTPヘッダへ加えるCGIスクリプトの形式です。Set-Cookie: name=value; expires=date; path=path; domain=domain_name; secure
- name=value
- このストリングはセミコロン(;)、コンマ(,)、半角スペースを除いたアルファベットの羅列で構成されます。もし、これらのnameやvalueへデータを入れる場合、暗号化が必要というわけではありませんが、URLスタイルの%XXなどを使うことをお勧めします。なお、Set-Cookieヘッダでは、これが唯一必要な属性です。
- expires=date
- expires属性はcookieの有効期限を日にちで指定します。有効期限がくるとcookieはもはや保存されず、外部へ情報を送りません。expires属性のdate引数(ストリング)は次のような形式となっています。
Wdy, dd-Mon-yy hh:mm:ss gmtこの形式はRFC 850、RFC 1036、RFC 822に基づいており、さまざまなバリエーションがある中で時間の指定のみグリニッジ標準時間(GMT)を用い、他の日にちの要素とダッシュ(-)で区切らなくてはなりません。expires属性が指定されない場合、cookieはユーザとのセッションが終わった時点で期限切れとなります。
ネットスケープ1.1以前のバージョンではバグがあり、cookiesに指定したpath属性の"/"はexpires属性が指定された場合のみ、セッション後も保存されます。
- domain=domain_name
- リストから有効なcookiesを捜す時、そのdomain属性は引っかかったURLをホストのドメインネームと比較します。最後が一致すれば、cookieは情報を送るべきかどうかpathを調べて判断します。「最後が一致する」ということは、たとえホストのフルドメインネームが違ってもdomain属性は一致するという意味です。たとえば、"acme.com"のdomain属性なら"anvil.acme.com"や"shipping.crate.acme.com"のホスト名とも一致します。
特定のドメイン内のホストのみがドメインのためのcookieを設定でき、またドメインは".com"、".edu"、"va.us"といった形式のドメインを防ぐため、そこへ最低2つか3つのピリオド(.)が必要です。"com"、"edu"、"net"、"org"、"gov"、"mil"、"int"という7つのトップレベルでのドメインであれば、2つのピリオドしか必要ありません。ドメインのデフォルト(初期設定)値はcookieの交信を起こすサーバーのホスト名です。
- path=path
- path属性はcoockieが有効かどうか、ドメインにおけるURLのサブセットを特定するため用いられます。もし、cookieがドメインとマッチしていたならばURLのパス名はpath属性と比較され、それもマッチした場合、有効なcookieと見なされてURLのリクエストとともに送られます。"/yok"というpathは"/yokbar"や"/yok/bar.html"とマッチし、もっとも一般的なのが"/"というpathです。特定のpathを指定しない場合、cookieを含むヘッダで示された文書と同じpathに見なされます。
- secure
- cookieへsecureと記されていれば、ホストとセキュリティ・チャンネルでつながっている場合のみ送信されます。つまり、今のところsecure cookiesはHTTPS(SSL上のHTTP)でしか送れません。また、secureが指定されていないと、cookieはセキュリティのないチャンネルで送っても安全だと判断します。
HTTPリクエストヘッダのシンタックス(Cookie)
HTTPサーバからURLのリクエストがあった時、ブラウザ(閲覧ソフト)はURLをすべてのcookieと照合し、マッチしたすべてのcookieのname/valueを含む行がHTTPのリクエストへ含まれます。形式は以下のとおりです。
Cookie: name1=opaque_string1; name2=opaque_string2 ...追記
複数のSet-Cookieヘッダが単独のサーバからの交信で発行できます。 同じpathとnameの場合はお互いの間で上書きされ、一番新しいものが引き継ぎます。また、同じpathで違うnameの場合は、新たなマッピング(path指定)が追加されます。 pathへさらにレベルの高いvalueを指定しても、より詳しい相手のpathマッピングを上書きしません。もし与えられたcookieとnameだけ一致してpathは違うものが2つ以上マッチすれば、マッチしたものはすべてが送られます(下記の例を参照)。 expiresヘッダはクライアントへ、いつならクライアントが要求されなくてもマッピングを削除して大丈夫かを知らせます。いっぽうクライアントは、期限切れの前であろうとcookieの数が限界を超えた場合など自分でcookieを削除することは可能です。 cookieをサーバへ送る時、より詳しいpathのマッピングが先行し、簡単なものは後回しとなります。たとえば、同時に送られた場合、pathのマッピングが"/"で"name1=yok"というcookieは、pathのマッピングが"/bar"で"name1=yok2"というcookieの後から送り出されます。 クライアントが1度に蓄えられるcookieは数などの制約があります。次はクライアント側で受け取り、蓄えられる最低量です。
- 合計300のcookie
- cookie1つあたり4キロバイト(名前とopaque_stringを合わせて書き込めるのが4キロバイトまで)
- サーバあるいはドメイン1軒あたり20のcookies(ホストとドメインが完全に指定された場合は単独で扱われ、それぞれの制限数が20づつ)
サーバはクライアントへこれらの制約以上を望めません。300のcookieかサーバあたり20のcookieという限界を超えればクライアント側で最近使ったcookieが削除され、4キロバイトより大きいcookieは強制的にそのサイズへ収められます。ただし、サイズが4キロバイトである限りnameはそのままです。
CGIスクリプトがcookieの削除を求めた場合、同じnameのcookieを返すことでそれを行い、返されるcookieのexpiresは過去の時間となります。ただ、期限切れのcookieを有効なcookieと置き換えるためpathとnameが完全にマッチしなくてはならず、そのcookieの創始者以外の者が削除することは困難です。 proxyサーバとしてHTTPを受ける時、Set-cookieのレスポンスヘッダは受け取りません。 仮にproxyサーバへSet-cookieヘッダを含む返答があったとしたら、クライアントへ返すSet-cookieヘッダに304(Not Modified)か200(OK)などの注意があるはずです。同じくクライアントのリクエストは、もしcookieのヘッダを含んでいるなら、それがリクエスト後に書き替えられていようとproxy経由で送り出されなくてはなりません。
例
cookieの使い方が理解しやすいよう、次に交信例をあげておきます。
交信例その1
- クライアントが文書をリクエストし、以下の返答を受けます。
Set-Cookie: customer=wile_e_coyote; path=/; expires=Wednesday, 09-Nov-99 23:12:40 gmt- クライアントがURLをこのサーバのパス名("/")でリクエストすれば、それは以下のような形で送られます。
Cookie: customer=wile_e_coyote- クライアントが文書をリクエストし、以下の返答を受けます。
Set-Cookie: part_number=rocket_launcher_0001; path=/- クライアントがURLをこのサーバのパス名("/")でリクエストすれば、それは以下のような形で送られます。
Cookie: customer=wile_e_coyote; part_number=rocket_launcher_0001- クライアントが以下を受け取ります。
Set-Cookie: shipping=fedex; path=/yok- クライアントがURLをこのサーバのパス名("/")でリクエストすれば、それは以下のような形で送られます。
Cookie: customer=wile_e_coyote; part_number=rocket_launcher_0001クライアントがURLをこのサーバのパス名("/yok")でリクエストすれば、それは以下のような形で送られます。Cookie: customer=wile_e_coyote; part_number=rocket_launcher_0001; shipping=fedex交信例その2
- 上記がすべてクリアになったと仮定し、クライアントが以下を受け取ります。
Set-Cookie: part_number=rocket_launcher_0001; path=/- クライアントがURLをこのサーバのパス名("/")でリクエストすれば、それは以下のような形で送られます。
Cookie: part_number=rocket_launcher_0001- クライアントが以下を受け取ります。
Set-Cookie: part_number=riding_rocket_0023; path=/ammo- クライアントがURLをこのサーバのパス名("/ammo")でリクエストすれば、それは以下のような形で送られます。
Cookie: part_number=riding_rocket_0023; part_number=rocket_launcher_0001
ここでは"/ammo"というマッピングに加えて"/"のマッピングがあるため、"part_number"と呼ばれるname/valueは2組存在します。