HTTP Cookie 関係でちょっとハマったので、覚え書き。
1. path= でパス(厳密には「URLのサブセット」)を指定する場合、リクエストのURIにそのパスが含まれていなければなりません。
考えてみれば当たり前なんですが。
たとえば、http://www.example.com/dirA/setcookie.cgi というCGIプログラムがクッキーを設定しようとした場合を考えてみます。
(クライアントが受け入れてくれるクッキーの例) Set-cookie: DATA=1; path=/ Set-cookie: DATA=1; path=/dirA/ (クライアントに拒否されるクッキーの例) Set-cookie: DATA=1; path=/dirB/
つまり、自分のいるディレクトリやその上層だったらいいけど、「自分がいるディレクトリツリーの外」に対してクッキーを発行するのはNG。セキュリティ的・プライバシー的に理にかなった制限です。
が、ブラウザによっては受け入れちゃうものもある模様。というか初めこの制限を知らなくて、「クッキーを受け入れてくれないブラウザがある」ことを知って調べてみたところ、むしろ受け入れるべきでないことが判明して驚きつつ納得した次第。
RFC的にはどうなっているかと言うと...なんとHTTP Cookieに関するRFCがない!
正確に言うと、ないわけじゃないんですが、現在HTTP Cookieについて書かれているのは、2000年10月に発行されたRFC 2965(日本語訳)。ただしこれは「Set-Cookie2:」という見たことのないレスポンスヘッダを定義していて、使われているのをみたことがありません。
このRFC 2965によって廃案にされたのがRFC 2109(英文)。こちらは「Set-Cookie」ヘッダについて記述されていますが、ふだん目にする書き方とは細かいところで違いがあり、互換性の面で不安があります。
というわけで、実質的には、Netscape社がNetscape Navigatorにオリジナル機能として実装したときのドキュメントまで戻るしかないようです。(原文・日本語訳)
ところがこのNetscape社のドキュメントでは、pathが異なる場合について規定がありません。なのでブラウザによって対応がまちまちなのも仕方ないところ。
RFCのほうは、2965も2109もどちらも、そういう場合はブラウザは「拒否するものとする」と書かれていました。
2. 「短い時間(たとえば1分)しか有効でないCookie」などは発行すべきではありません。
RFCで規定されているCookieは、「Max-Age=60」などと書けば「有効時間60秒」のCookieが発行できます。それなら問題はないのですが、Netscape社のドキュメントでは「Max-Age」は規定されていません。となると、理解してくれないブラウザもありそうなので、「Max-Age」で指定する方法は避けたいところです。
Netscape社のドキュメントでは、「expires=Wdy, DD-Mon-YYYY HH:MM:SS GMT」と書くことで、指定時刻まで有効なCookieを発行できます。じゃあ例えば、現在時刻が00:00:00だとして、「有効期限が00:01:00までのCookie」を発行すれば「60秒間だけ有効なCookie」になるのでは? と思った私が浅知恵でした。
なぜかというと、「サーバの時計とクライアントの時計が同期しているとは限らない」からです。
先の例でいうと、サーバの時刻が00:00:00だったので「00:01:00まで有効」なCookieを発行したとしましょう。ところがクライアントの時計が進んでいて、すでに00:01:10だったとします。するとクライアントのブラウザにとってこのCookieは、有効期限が「10秒前まで」となってしまうのです。有効期限が過去のCookieは、当然ブラウザに保存されません。
というわけで、最近はNTPの普及もあってクライアントの時計もそうそうズレてはいないでしょうが、それでも数分のズレは珍しくないと思うべきでしょう。また、PSPのような携帯端末での利用を想定する場合、クライアントは思いっ切り時刻が狂っている場合も少なくないので、さらに注意が必要です。
なお、どうしても厳密に運用したい場合は、クライアントの時刻をサーバ側にいったん送ってもらった上で(JavaScript等が必要になるかもしれません)、「その時刻プラス60秒(プラス往復のタイムラグを加味)」を有効期限としてレスポンスするという手もあります。
以上、Cookieのワナ2題でした。