理系学生日記

おまえはいつまで学生気分なのか

Cookieのpath属性に対するブラウザ毎の挙動の違い

ブラウザ毎の Cookie の path に対する挙動の違いによって、検証しているアプリに色々とバグっぽい挙動が出てきたので、あらためて Cookie における挙動をまとめてみます。

検証内容

  • セットするCookie の path 属性に /path、あるいは /path/ を指定した Web アプリを作成
  • 個々のブラウザで、次のパスにアクセスし、Cookie が送信されるかどうかを確認
    • /path
    • /patha
    • /path/
    • /path/a

このへんのアプリだったら Perl とかでサクっと作った方が早いので、PSGI アプリとして実装しました。 だいたい以下のようなかんじです。

#!/usr/bin/env perl
use Plack::Builder;
use Plack::Request;
use Plack::Middleware::Session::Cookie;

my $app = sub {
    my $env = shift;

    my $req = Plack::Request->new($env);
    my $cookies = $req->cookies;
    my $res = $req->new_response(200);

    $res->body(%{$cookies}? 'cookie sent' : 'no cookie');
    $res->finalize;
};

builder {
    enable 'Session',
        state => Plack::Session::State::Cookie->new(path => '/path');
        # path は '/path' と '/path/' の双方を試した
    $app;
}

まずは結果を

○ が「Cookie が送信された」、- が「Cookie は送信されなかった」ことを表現しています。 挙動が大きく違っていたのは IE 11 だったんですが、家に Windows がないので、調べることができませんでした。

後述しますが、Chrome と Safari は、RFC 6265 に沿っています。 FIrefox もほぼ沿っているんですが、Cookie の Path の末尾が / の場合に、RFC 6265 と挙動が異なるように見えます。

path=/path

ブラウザ /path /patha /path/ /path/a
Chrome 61.0.3163.100 -
Firefox 56.0.2 -
Safari 11.0 (12604.1.38.1.7) -

path=/path/

ブラウザ /path /patha /path/ /path/a
Chrome 61.0.3163.100 - -
Firefox 56.0.2 -
Safari 11.0 (12604.1.38.1.7) - -

RFC はどうなのか

Cookie について定義しているのは RFC 6265 ですが、この 5.1.4. Paths and Path-Match に、 path をどのようにしてマッチさせるべきなのかの定義があります。

詳細は見て頂ければ良いのですが、まず最初に、cookie の path と比較する対象として、uri-path を定義します。 これは、リクエスト URI のうち、ホスト名の後の / からクエリパラメータの ? より前の最後の / の前までと url-path とされています。 - /hoge/fuga/piyo なら /hoge/fuga - /hoge なら /

これに対し、cookie の path が以下のどれかを満たすなら、そのときに cookie が送出されます。 読めばなるほどなぁと分かるんですが、これを日本語で簡潔に説明すると難しいので、読んで頂いた方が誤解がないと思います。

   o  The cookie-path and the request-path are identical.

   o  The cookie-path is a prefix of the request-path, and the last
      character of the cookie-path is %x2F ("/").

   o  The cookie-path is a prefix of the request-path, and the first
      character of the request-path that is not included in the cookie-
      path is a %x2F ("/") character.

参考文献