間があいてしまいましたが続きです。

前回書いた様な経緯で、某会員制サイトにログインできない原因を自力で調べることにしました。

前回書いたとおり、原因として一番怪しいと考えられるのはProxyサーバだったので、
ログイン成功時と失敗時それぞれの通信を解析すれば解決の糸口が見えてくるのではと思い、通信パケットのキャプチャを取ることにしました。

通信パケットのキャプチャには、フリーのFiddlerを使用しました。


Fiddlerを使用してキャプチャした結果は以下の通りでした。

ログイン失敗時のパケットキャプチャ


失敗時のパケットキャプチャ

ログイン成功時のパケットキャプチャ


成功時のパケットキャプチャ

成功時と失敗時を比較してみると、
それぞれ同一のキーに対して2回Set-Cookieを行っていて、
成功時は"deleted"を設定しているのが先に、
セッションキーと思われる文字列を設定していのが後に来ているのに対して、
失敗時は"deleted"が後に来ていました。


そして、失敗環境にはtinyproxyの文字が。


以上の事から会員サイトのlogin.phpでは、
以下のようなコードが書かれているのだろうと予想できました。


<? // login.php
// まずは以前のセッションキーを削除
setcookie("***_admit_user","");
if(認証情報がOKならば)
{
setcookie("***_admit_user","新規発行のセッションキー");
}
?>

※setcookieで空文字を指定すると、HTTPヘッダには値を'deleted' に変更して有効期限を 1 年前に設定した形で書き出されるそうです。

概要は以下のような感じです。


1、一つのPHP内で同一キーに対して2回setcookieが実行されている。
2、setcookieの内容はHTTPヘッダに書き出される。PHP自体は同一キーの複数回同時設定を推奨していないが、一応実行した順番にHTTPヘッダに書き出される。
3、パケットに変更が無く受け取れる環境であれば、発行されたセッションキーはクッキーに保存される。
4、対してProxyサーバが通信を仲介する場合には、仲介時にパケットの再構築を行っており(パケットの内容に検閲をかけてる?)、その時にHTTPヘッダの項目にソートがかけられているため、Cookieの順番が入れ替わってセッションキーを登録した後にすぐ削除されてしまっている。


結論としては、

単一PHP内で同一キーに対して複数回setcookieしてはいけない。
 → ひとつのHTTPレスポンス内に同一なキーのCookieの設定が複数回入るようなコードを書いてはいけない。

と言う事です。

修正コードを書くとこんなかんじです。


<? // login.php
if(認証情報がOKならば)
{
setcookie("***_admit_user","新規発行のセッションキー");
}
else
{// 認証情報NG
// 認証NGなので以前のセッションキーも削除しておく
setcookie("***_admit_user","");
}
?>


以上のような事をメールで送ったところ、"検討します"と返信が返って来て、1?2週間後には自宅から問題なくアクセスできるようになっていました。

念のためFiddlerでパケットキャプチャしなおして検証してみたら、
Cookieの複数回設定もなくなっていました。

めでたしめでたし。