Cookieの概要と使い方

 Web アプリケーションを作る上では欠かせないCookie。本コーナーでは Cookie の仕組みを詳しく説明し、Perl スクリプトでの実装方法を簡単に解説していきます。

目次

Cookie とは?

Cookie とは、サーバとの通信において、特定の情報をクライアント(ブラウザー)に保持させるものです。これにより、次回、同じサイトに訪れたとき、あなただけのカスタマイズされた画面を表示させたり、オンラインショッピングではショッピングカートとしても使われます。

Cookie を使うことによって、多彩な機能を実現することができますので、CGI を作成するにあたっては非常に便利な機能です。

Cookie の仕様は、Netscape Communications Corporation が、 http//home.netscape.com/newsref/std/cookie_spec.html で公開しております。futomi's CGI Cafeでは日本語訳を公開しておりますので、参考になれば幸いです。

Cookieってどこに保存されるの?

さて、いろいろなサイトをブラウザーで見ていると、実は非常に多くの Cookie を仕込まれているものです。Microsoft Internet Explorer や Netscape Communicator のデフォルト設定では、Cookie を受け付けたり、サーバへ送信する際に警告を出さないようになっています。そのため、知らず知らずのうちに、あなたのブラウザーは Cookie をたくさん食べてしまっているのです。

では食べてしまった Cookie は何処にあるのでしょうか。Internet Explorer と Netscape Communicator それぞれについて消化してしまった Cookie までご案内いたしましょう。

Internet Explorer

Windows 2000, Windows XP の場合

\Documents and Settings\ログオン名\Local Settings\Temporary Internet Files\○○
\Documents and Settings\futomi\Cookies\○○.txt

Winodws Meの場合

\WINDOWS\Temporary Internet Files\○○
\WINDOWS\Cookies\○○.txt

Netscape Communicator

\Program Files\Netscape\Users\ユーザ名\cookies.txt
# 「ユーザ名」の部分は、プロファイルを使っていない場合「default」となります。

Cookie を食べてみましょう

 具体的に Cookie を受け付けるとはどういうことかを実験してみましょう。実験の前に、前述した Cookie の保存場所を開いておいてください。

Cookie の実験

画面を開くと、クッキー名と値の表が表示されますが、まだ何も表示されていませんね。では Cookie を食べてみましょう。ここでは「クッキーをセットする」ボタンを押してみてください。具体的にどんなクッキーを受け入れたのかが表示されますね。

Set-Cookie: CookieTest1=%83e%83X%83g%82P; expires=Wed, 03-Apr-2002 09:56:27 GMT;
Set-Cookie: CookieTest2=%83e%83X%83g%82Q; expires=Wed, 03-Apr-2002 09:56:27 GMT;

これはサーバ側からクライアント(ブラウザー)に対して Cookie をセットする際に送るリクエストヘッダーです。これを受けて、ブラウザーはクッキーをセットします。

では、セットされたクッキーを覗いてみましょう。ここではパソコンに保存されたクッキーを見るのではなく、サーバへ送られたクッキー情報を覗いてみます。「クッキーを見る」ボタンを押してみてください。

クッキー名
CookieTest1 テスト1
CookieTest2 テスト2

こんな画面が表示されましたね。ブラウザーは、クッキーをセットされたサーバへアクセスするたびに、そのクッキー情報をサーバへ送っているのです。

ではパソコンに保存された Cookie を見てみましょう。先ほど開いておいた Cookie 保存場所を見てください。そのウィンドウをアクティブにした状態で「F5」を押して最新の情報にして下さい。

Internet Explorer の場合、新たにテキストファイルが出来上がりましたね。これが保存された Cookie です。Internet Explorer の場合は、サーバごとに別々のファイルが出来上がります。このファイルの中身はこのような感じになっているはずです。

CookieTest1
%83e%83X%83g%82P
www.futomi.com/cgi-bin/lecture/
0
1881150208
29414327
1122876704
29414126
*
CookieTest2
%83e%83X%83g%82Q
www.futomi.com/cgi-bin/lecture/
0
1881150208
29414327
1122876704
29414126
*

Netscape Navigator の場合、「Cookie.txt」にすべての Cookie が保存されます。ファイルをダブルクリックして中身をのぞいてみると、

www.futomi.com FALSE /cgi-bin/lecture FALSE 988884260 CookieTest1 %83e%83X%83g%82P
www.futomi.com FALSE /cgi-bin/lecture FALSE 988884260 CookieTest2 %83e%83X%83g%82Q

という行がありますね。これが先ほどセットされた Cookie 情報です。

Cookieをブラウザーで確認するには

 いつも知らず知らずのうちに仕込まれてしまう Cookie ですが、Netscape の設定で都度確認画面を出すことができます。残念ながら Internet Explorer ではできません。

まず、Netscape Communicator の設定を変更しなければいけません。ツールバーから「編集(E)」→「設定(E)...」を選択してください。カテゴリ欄の「詳細」を選択すると、右側に詳細設定画面が表示されます。ここの「Cookie」の欄で「cookieを受け付ける前に警告する(W)」にチェックを入れてください。

これで、下図のとおり、Cookie を受け付ける都度、確認画面が出てくるようになります。(普段は非常にうっとうしいですがね…)

Netscape Cookie Dialog

Cookieをセットするには

Cookie をセットするには、Java スクリプトでも可能ですが、ここでは Perl で作る CGI でどうすればいいかを解説します。先ほどのレスポンスヘッダーをもう一度ご覧下さい。実際には、以下の文字列をレスポンスヘッダーとしてブラウザーに返します。

Set-Cookie: CookieTest=%83e%83X%83g; expires=Tue, 01-May-2001 11:32:58 GMT;
Content-Type: text/html

以下、HTMLが続く

Perl スクリプトで出力する際には、

print 'Set-Cookie: CookieTest=%83e%83X%83g; expires=Tue, 01-May-2001 11:32:58 GMT;';
print 'Content-Type: text/html',"\n";
print "\n";
print "以下、HTMLが続く\n";

のようになります。

これはあくまでも例ですが、基本的に次に示すような文法で、サーバからクライアントへレスポンスヘッダーに加えます。

Set-Cookie: クッキー名=クッキー値; expires=有効期限; domain=ドメイン名(サーバ名); path=パス; secure

 それぞれの意味は以下のとおりです。

クッキー名=クッキー値 ブラウザーに保存したい変数名とその値をセットします。スペース、カンマ、セミコロンは含まれてはいけません。そのため URL エンコードをする必要があります。(後述) Cookie をセットする際には、この項目のみが必須です。
expires

クッキーの有効期限をセットします。有効期限は GMT で指定します。フォーマットは以下のとおりです。

Wdy, DD-Mon-YYYY HH:MM:SS GMT

有効期限が省略されると、テンポラリークッキーとして扱われます。つまり、ブラウザーを閉じた時点で、そのクッキーは無効となります。(後述)

domain

セットしたクッキーが送信されるドメインを指定します。サーバ名で指定すれば、指定サーバへのアクセスの時だけセットしたクッキーを送信します。ドメインが省略されると、そのときアクセスしたサーバ名がセットされます。

先ほどの実験でアクセスした URL は、

http://www.futomi.com/cgi-bin/lecture/cookietest.cgi

です。このとき、domain を省略すると、www.futomi.com がセットされます。

path

セットしたクッキーが送信されるパスを指定します。パスが省略されると、アクセスしたリソース(HTML、CGI)のパスがセットされます。

先ほどの実験でアクセスしたURLは、

http://www.futomi.com/cgi-bin/lecture/cookietest.cgi

です。このとき、path を省略すると、/cgi-bin/lecuture/ がセットされます。

secure この項目が指定されていると、アクセス先が SSL などのような安全なサイトの場合のみにクッキーを送信するようになります。ドメイン、パスが一致したとしても、アクセス先が安全とみなされないと、クッキーを送信しません。

domain, path の補足

ブラウザーに保存された Cookie は、サーバ側の要求あるなしにかかわらずサーバへ送信されます。しかし、domain と path に一致した場合にのみ Cookie をサーバへ送信します。domain, path を省略すると、その Cookie をブラウザーにセットした CGI の domain と path が設定されますので、同じサーバでかつ、同じパス配下にアクセスしたときだけその Cookie をサーバへ送信します。

しかし、Cookie をセットした CGI 以外のリソースにアクセスしたときも、その Cookie 情報を得たい場合があります。そのときは、どうすればいいのでしょう。具体的に、今回の実験で説明します。

Cookie をセットした CGI のURLは、「http://www.futomi.com/cgi-bin/lecture/cookietest.cgi」です。今回の実験では、その Cookie を取得する CGI も同じですので、問題はなかったのです。しかし、「http://www.futomi.com/cgi-bin/test/cookieget.cgi」にアクセスしたときに、その Cookie を取得するにはどうすればいいのでしょうか。この場合、パスが /cgi-bin/test/ であるのに対し、Cookie をセットしたパスが /cgi-bin/lecture/ ですので、その Cookie 情報をサーバへ送信しません。これを /cgi-bin/test/  にアクセスしたときにも送信するような path で明示的に Cookie をセットしなければいけません。この場合には、 path=/cgi-bin/ とすればいいのです。こうすれば、/cgi-bin/ 配下のすべてのリソースにアクセスしたときに、Cookie 情報をサーバへ送信することになるのです。極端なことをいうと、path=/ としてしまうと、www.futomi.com すべてのリソースにアクセスしたときすべてにCookie 情報を送信することになるのです。

Cookie は、場合によっては、プライバシーにかかわる情報をセットする場合があります。やはり、無駄に Cookie 情報をサーバに送りつけるのは、セキュリティーの観点からも危険です。前述の例のように path=/ とした場合、もしサーバがプロバイダーが提供する共用のサーバだった場合には、同じサーバを利用している他のユーザのホームページへアクセスした場合にも Cookie を送信してしまうのでう。もし、明示的に domain, path を指定する場合には、できる限り、domain, path を厳密に指定したほうがいいのです。

name, value の URL エンコード

クッキー名とクッキー値には、スペース、カンマ、セミコロンを含めてはいけません。そのような文字が出現しないようにエンコードする必要があります。今までの例でもお気づきのとおり、URLエンコードをしてからセットしなければいけません。本来「テスト」の部分が、URLエンコードをして「%83e%83X%83g」をとなっていますね。Perlスクリプトで URL エンコードするには以下のコードで実現できます。

$CookieValue = 'テスト';
$CookieValue =~ s/([^\w\=\& ])/'%' . unpack("H2", $1)/eg;
$CookieValue =~ tr/ /+/;

URL エンコードは、RFC2396 で定義されています。

ブラウザーから送信された Cookie を CGI で受け取るには

ブラウザーから送信された Cookie を CGI で受け取るには、環境変数 $ENV{'HTTP_COOKIE'} を使います。ブラウザーから送信された Cookie 情報はすべて $ENV{'HTTP_COOKIE'} に格納されますので、この値を見れば Perl スクリプト内で、その値を使うことができるのです。

先ほどの実験でも、$ENV{'HTTP_COOKIE'} の値がそのまま表示されますので、ご確認ください。以下のような値が表示されているはずです。

環境変数 HTTP_COOKIE
CookieTest1=%83e%83X%83g%82P; CookieTest2=%83e%83X%83g%82Q

実験では2つのクッキーをセットしました。「クッキー名=クッキー値」のペアーが、セミコロンで区切られていますね。さらにセミコロンの後ろに半角スペースが入ります。もし3つ以上あっても同様に、セミコロンと半角スペースで区切られます。逆に1つだけの場合には、最後にセミコロンと半角スペースはつきません。

今回の実験では、クッキー値が URL エンコードしてありますので、これをデコードしないと意味がわかりません。次に URL エンコードされたクッキー値を、デコードする方法をご案内します。

name, valueのURLデコード

URL デコードは、以下のコードで実現できます。

$CookieValue =~ s/\+/ /g;
$CookieValue =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C",hex($1))/eg;

Cookie を無効にするには

CGI を使って、クライアント(ブラウザー)にセットされた Cookie を無効にするにはどうすればいいのでしょうか。これは、その Cookie をセットしたときと同じ Cookie ヘッダーをクライアントへ送信すればいいのですが、有効期限を過去の時間にすればいいのです。そうすることで、ブラウザーは Cookie 情報をサーバへ送信することをしなくなります。過去の時間であればいつでも問題ありません。

expires=Thu, 01-Jan-1970 00:00:00 GMT

一時的な Cookie

Cookie ヘッダに expires を省略することで、テンポラリー Cookie をセットすることができます。テンポラリー Cookie とは、ブラウザーを閉じた時点で、無効になってしまいます。パスワードを入力させて、そのブラウザーを開いているときだけ CGI への要求を受け付けるようなアプリケーションに有効です。

では実験してみましょう。

Cookie の実験

先ほどの実験とまったく同じ画面ですので、Cookie をセットしたあと、Cookie を見てみてください。再度、今開いているブラウザーを閉じ、再度起動してから、実験ページを見てみてください。すると、Cookie がサーバへ送信されていないのがわかりますね。

このテンポラリー Cookieは、ファイルに保存されません。