Perl/CGI研究室 'PERL-LABO'

Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

クッキーの衝突の研究

研究内容

前回の研究で同じクッキーを複数のCGIプログラムで共有するできることが分かりました。 ということは、逆に異なるCGIプログラムで意図しないクッキーの共有が起きたとき、 クッキーが衝突しちゃうということだと思います。その辺を研究してみます。

詳細

こういう場合について調べます

CGIプログラムAが「クッキーA」というクッキーを書き込んだとしましょう。 次に、同じフォルダにあるCGIプログラムBが「クッキーB」というクッキーを書き込んだとします。 すると、最初に書き込んだ「クッキーA」は「クッキーB」で上書きされてしまうんでしょうか? …たぶん、上書きされると思いますけど確かめてみましょう。

こういう場合も調べてみましょう

CGIプログラムAが「クッキーA」というクッキーを書き込んだとしましょう。 次に、下のフォルダにあるCGIプログラムBが「クッキーB」というクッキーを書き込んだとします。 CGIプログラムが置かれたフォルダの位置関係から、 CGIプログラムAが書き込んだクッキーはCGIプログラムBで読み込むことができますが、 CGIプログラムBが書き込んだクッキーはCGIプログラムAで読み込むことができません。 ということは、CGIプログラムBが「クッキーB」というクッキーを書き込むと、 CGIプログラムAが受け取るクッキーはどうなるんでしょう?消えてしまうのか、 残るのか?

結果

現在のクッキーを表示しつつ「クッキーA」というクッキーを書き込むCGIプログラムと、 現在のクッキーを表示しつつ「クッキーB」というクッキーを書き込むCGIプログラムを作りました。

作成したCGIプログラム

a.cgi (CGIプログラムA)
#!/usr/bin/perl

$newcookie = "クッキーA";

print "Content-type: text/html\n";
print "Set-Cookie: $newcookie\n";
print "\n";
print "受け取ったクッキー=$ENV{'HTTP_COOKIE'}<br>";
print "書き込んだクッキー=$newcookie";
b.cgi (CGIプログラムB)
#!/usr/bin/perl

$newcookie = "クッキーB";

print "Content-type: text/html\n";
print "Set-Cookie: $newcookie\n";
print "\n";
print "受け取ったクッキー=$ENV{'HTTP_COOKIE'}<br>";
print "書き込んだクッキー=$newcookie";

実行結果

下のリンクをクリックしてみてください。

(1) プログラムAを実行し「クッキーA」を書き込むとともに現在のクッキーを表示します。
(2) プログラムBを実行し「クッキーB」を書き込むとともに現在のクッキーを表示します。
(3) 下のフォルダのプログラムBを実行し「クッキーB」を書き込むとともに現在のクッキーを表示します。

考察

同じフォルダのCGIプログラムによるクッキーの衝突

最初に (1) をクリックして「クッキーA」を書き込みます。 次に (2) をクリックすると、受け取ったクッキーは「クッキーA」。これは予想通り。 同時に、「クッキーB」が書き込まれます。 そして再度 (1) をクリックすると、受け取ったクッキーは「クッキーB」でした。 一応、予想通りでしたが、クッキーを共有している2つのCGIプログラムによって、 クッキーが上書きされていることが確認できました。

ということで、クッキーを使うCGIプログラムを作る時は、 同じフォルダに別のクッキーを使うCGIプログラムを置くと、 クッキーが上書きされてしまうので注意しないといけないっていうことが確認できました。 クッキーの共有っていうのは便利ですが、こういうデメリットもあるわけですね。 他のCGIプログラムが書き込んだクッキーを壊さないように注意しないといけないというか、 他のCGIプログラムによってクッキーが上書きされている可能性に注意しないといけないというか…。

でも、他のCGIプログラムによってクッキーが変更されていたら基本的に困りますよね。 ですから、クッキーを使うCGIプログラムは、他のプログラムとは別のフォルダに置くようにして、 意図しないクッキーの衝突が起きないように配慮することが必要ということになります。

下のフォルダのCGIプログラムによるクッキーの衝突

最初に (1) をクリックして「クッキーA」を書き込みます。 次に (3) をクリックすると、受け取ったクッキーは「クッキーA」。これは予想通り。 同時に、「クッキーB」が書き込まれます。 そして再度 (1) をクリックすると、受け取ったクッキーは「クッキーA」。 元のままでした。

下のフォルダに置かれたCGIプログラムが書き込んだクッキーは 受け取れないわけですが、ちゃんと元のクッキーが残っていました。へぇー。 つまり、下のフォルダに置かれたCGIプログラムがどんなクッキーを書き込もうが、 上のフォルダにあるCGIプログラムは一切影響を受けないということです。 よくできてますね。この時点では、クッキーの衝突は起きていません。

この次が、ちょっと複雑です。再度 (3) をクリックすると、 受け取ったクッキーは「クッキーB; クッキーA」でした。 これはつまり、自分が書き込んだ「クッキーB」に加えて、上のCGIプログラムが書き込んだ 「クッキーA」も受け取っている、ということです! 2つのクッキーが、; で区切られてCGIプログラムに渡されています。 うーん。なるほど。

CGIプログラムは、自分よりも上の階層のCGIプログラムがどんなクッキーを書き込んでいるかなんて 知らないですよね(知っている場合もあると思いますけど)。 ですから、CGIプログラムの置き方によっては、クッキーを読み込んだら、 自分が書き込んだクッキーに加えて、なんか自分の知らないクッキーも受け取ってしまうことがあるということです。 ; の後ろは自分の知らないクッキーですから、これを無視しないといけません。 一方、意図的に、上のCGIプログラムが書き込んだクッキーを下のCGIプログラムで利用しようという場合を考えてみます。 下のCGIプログラムが上のCGIプログラムが書き込んだクッキーを受け取るだけなら問題ありません。 でも下のCGIプログラムもなにかクッキーを書き込む場合、 下のCGIプログラムは「自分のクッキー; 上のクッキー」という形でクッキーを受け取ることになります。 ですから、それを考慮して、; でクッキーを区切って処理する必要がありますね。

なんとなく分かりましたが、なんだか大変ですね。

さらに深い階層のCGIプログラムによるクッキーの衝突

今は、2つのCGIプログラムの場合でしたが、これが3つ、4つと増えたらどうなるんでしょうか。 ちょっと試してみましょう。

(1) プログラムAを実行します。
(2) 下のプログラムBを実行します。
(3) 下の下のプログラムCを実行します。
(4) 下の下の下のプログラムDを実行します。

上から順番に実行していくと、最終的に一番下のプログラムDが受け取るクッキーは 「クッキーD; クッキーC; クッキーB; クッキーA」となります。 (自分が書き込んだクッキーを表示するためにプログラムDを2回実行しています。) ; で区切られて、上の階層のCGIプログラムが書き込んだクッキーが並んでいますね。 順番は、自分が最初、1つ上、2つ上…となっているようです。

試しに、ブラウザを全部閉じてクッキーを初期化してから(有効期限を設定していないので、 有効期限はブラウザを閉じるまでになります)、逆に下から順番に、プログラムBを飛ばして実行してみると、 最終的にプログラムDが受け取るクッキーは「クッキーD; クッキーC; クッキーA」となりました。 クッキーの並び方は、クッキーを書き込んだ順番は関係なくて階層が下のものが先になっていること、 それに、途中の階層でクッキーが存在していなくても「クッキーC; ; クッキーA」みたいな空欄になるわけでは ないっていうことが分かりました。

この仕組みを使ってクッキーの処理をするのなら、 クッキーの最初に書き込んだCGIプログラムのIDを書いておくとかすればいいのかも知れませんね。 例えば「ProgA=クッキーA; ProgB=クッキーB」みたいになっていれば、 複数のCGIプログラムが書き込んだクッキーを正しく処理できそうです。

自分が書き込んだ、あるいは自分と同じフォルダのCGIプログラムが書き込んだクッキーだけを処理するなら、 最初の ; までを取り出して処理するようにすればいいですね。 でもこの場合でも、自分がクッキーを書き込む前に、自分より上の階層のCGIプログラムが クッキーを書き込んでいた場合はそれを受け取ってしまうということに注意が必要かも知れません。 しかもそれが自分が書き込んだクッキーなのか上の階層のCGIプログラムが書き込んだクッキーなのか、 なにか識別できる仕組みを自分で作っておかない限り判断ができませんから、なかなか大変ですね。

まとめ - 最も簡単で確実なクッキーの衝突回避策

クッキーを複数のCGIプログラムで共有できるということはもちろんメリットがありますが、 クッキーの衝突というデメリットもあるということが分かりました。

このクッキーの衝突、なんだか複雑で完全に正しく処理するのは大変そうです。 ですから、結論として、最も簡単で確実なクッキーの衝突回避策は、 「クッキーを使うCGIプログラムは別のフォルダに置く!」これです。 同じフォルダのCGIプログラムにクッキーを上書きされるとか、 上のフォルダのCGIプログラムが書き込んだクッキーを受け取ってしまうとか、 そんなことは一切考えない。ただCGIプログラムを置くフォルダの位置関係に注意する。 クッキーを共有させる必要があるときにだけ、CGIプログラムを同じフォルダ、 または下のフォルダに置く。 下のフォルダのCGIプログラムは、クッキーを読み込むだけにするのが楽。 こんな感じでしょうか。 今回の研究、結構勉強になりました。 (^^

分かったこと

  1. 同じフォルダのCGIプログラムによってクッキーは上書きされます。
  2. 下のフォルダのCGIプログラムがクッキーを書き込んでも、上のプログラムには影響はありません。
  3. 下のフォルダのCGIプログラムは、上のプログラムが書き込んだクッキーも受け取ります。
  4. 上と下のCGIプログラムがそれぞれクッキーを書き込むと、下のCGIプログラムは
    「自分が書き込んだクッキー; 上のCGIプログラムが書き込んだクッキー」という形でクッキーを受け取ります。
  5. 階層が複数になると「一番下; その上; さらにその上…」というようにクッキーが並びます。
  6. ややこしいので、クッキーを使うCGIプログラムは別のフォルダに置くようにすればいいです。 (^^;
  7. 意図的にクッキーを共有したい場合でも、フォルダの上下関係があると複雑になるので
    同じフォルダにCGIプログラムを置くようにした方が簡単みたいです。
    (フォルダの上下関係を利用してクッキーを上手に処理するテクニックもあるのかな?)
Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

Copyright (c) 'PERL-LABO' All Rights Reserved.  リンクフリーです。