tokuhirom's Blog

HTTP::Session2 has been released.

English document is available on metacpan!

Following document is written for non-english speakers.


HTTP::Session2 を作成した。主に Amon2 で使用することを想定しているが、広く一般につかえるものと思う。

特徴

上記が、重要なことである。

弊社のようなハイトラフィックなサービスを運営している場合には、できるだけリソースをケチりたいので、そういう思想なものが必要となった。通常の用途では Plack::Session でも問題ないと思う。

クライアントサイドストレージとサーバーサイドストレージ

Cookie にデータを保存する形式と、サーバーサイドにデータを保存する形式には得失がある。

自分は、基本的に仕事ではサーバーサイドにデータをおくのが無難だと考えるが、趣味でやっているものについてはクライアントサイドでかまわないと考えている(多分に「慣れているから」という理由が大きいが)。

クライアントサイドストレージ

pros. サーバーサイドの設定がいらない

ディスクにデータをかいたりしなくてもいい。

cons. データの再送が可能となる

データそのものはクライアントがもっているので、過去に取得したセッションデータを再送可能である。

cons. 帯域を無駄につかう

大きめのデータを cookie ヘッダにいれた場合、すべてのリクエストに cookie データが付属するので帯域が無駄である。

cons. 開発時にはまる可能性がある

途中でセッションのデータ構造などを変えた場合に、古い cookie をたべているクライアントがおくってきたデータが原因ではまる可能性がある。

サーバーサイドストレージ

pros. データの管理が楽である。

セッションデータを全部クリアしたい、などといった場合には memcached の再起動なりなんなりだけですませられる。

XSRF と HTTP::Session2

今回、HTTP::Session2 では XSRFトークンの管理をセッションライブラリが引き受けることにしている。

AngularJS

AngularJSを利用している場合、HTTP::Session2 はAngularJSにあわせた名前でXSRFトークンをクッキーで送出しているので、他に何もする必要はない。自動的にアプリケーションがよしなにしている。

普通のWebアプリケーション

以下のようなJSをよみこめばよい。

document.addEventListener("DOMContentLoaded", function () {
    document.removeEventListener("DOMContentLoaded", arguments.callee, false);

    var xsrf_token = getXSRFToken();
    document.getElementsByTagName("form").forEach(function (form) {
        var method = form.getAttribute('method');
        if (method === 'get' || method === 'GET') {
            return;
        }

        var input = document.createElement('input');
        input.setAttribute('type',  'hidden');
        input.setAttribute('name',  'XSRF-TOKEN');
        input.setAttribute('value',  xsrf_token);
        form.appendChild(input);
    });

    function getXSRFToken() {
        var cookies = document.cookie.split(/\s*;\s*/);
        for (var i=0,l=cookies.length; i<l; i++) {
            var matched = cookies[i].match(/^XSRF-TOKEN=(.*)$/);
            if (matched) {
                returm matched[1];
            }
        }
        return undefined;
    }
}, false);

XSRFトークンの確認

以下のようにすればよい。

__PACKAGE__->add_trigger(
    BEFORE_DISPATCH => sub {
        my $c = shift;
        my $req = $c->req;

        if ($req->method ne 'GET' && $req->method ne 'HEAD') {
            my $xsrf_token = $req->header('X-XSRF-TOKEN') || $req->param('xsrf-token');
            unless ($session->validate_xsrf_token($xsrf_token)) {
                return [
                    403,
                    [],
                    ['XSRF detected'],
                ];
            }
        }
        return;
    }
);

StickyQuery のサポートについて

URI based session management は、セキュリティ上も問題があるし、Cookie を送信しないような DoCoMo の古い端末はもはや無視できると判断し、サポートしない。 必要であれば HTTP::Session 1 をご利用いただけばよい。

Amon2 6.00

Amon2 6.00 では、このライブラリがデフォルトのセッションライブラリとなる予定である。