Perl
Mojolicious

4.59から導入されたCSRF対策を使ってみる

More than 5 years have passed since last update.

現時点で最新のMojolicious「 4.59 」ではCSRF対策のメソッド諸々がようやく実装されました。以下Changesより引用。



  • Added CSRF protection support.

  • Added csrf_protect method to Mojolicious::Validator::Validation.

  • Added csrf_token attribute to Mojolicious::Validator::Validation.

  • Added csrf_token helper to Mojolicious::Plugin::DefaultHelpers.

  • Added csrf_field helper to Mojolicious::Plugin::TagHelpers.


Mojoliciousデフォルトのセッションを使うのでPlack::Middleware::Sesssionその他を使っている場合は有効にならないケースがありますが、カジュアルにCSRF対策をするにはよいでしょう。また内部のコードを追えば独自のCSRF-Protectionなヘルパーなどを自作するキッカケになるかもしれません。今回はMojolicious::Liteで試せるサンプルをつくってみました。

ポイントは..


  • テンプレートの中で csrf_token ヘルパーメソッドを呼び出してhidden-typeなフォームに入れる

  • ちなみにTagヘルパーを使う場合は csrf_field で一発

  • Mojolicious::Validator::Validationの csrf_protect メソッドでtokenのバリデーションを行う

  • セッション $self->session->{csrf_token} にtokenが収められているのでそれを参照して独自にチェックもアリ

って感じです。ではサンプルのコードをば。ちょいと冗長に書いてある部分あるっす。


前半のコード


#!/usr/bin/env perl
use Mojolicious::Lite;
use Mojolicious::Validator;
use Mojolicious::Validator::Validation;

get '/' => sub {
my $self = shift;
$self->render('index');
};

post '/post' => sub {
my $self = shift;
my $validation = $self->validation;
my $messages;
if ($validation->csrf_protect->has_error('csrf_token') ) {
push @$messages, 'Invalid CSRF Token!';
}
if ($validation->required('text')->has_error('text') ) {
push @$messages, 'Text is required!';
}
$self->stash->{messages} = $messages;
$self->render('result');
};

app->start;

__DATA__



後半のコード


@@ index.html.ep
% layout 'default';
<form action="/post" method="post">
<input type="text" name="text" placeholder="Text" />
<input type="hidden" name="csrf_token" value="<%= csrf_token %>" />
<input type="submit" value="Submit" />
</form>

@@ result.html.ep
% layout 'default';
% if ($messages) {
<b>Error!</b>
<ul>
% for my $message (@$messages) {
<li><%= $message %></li>
% }
</ul>
% }else{
<b>Success!</b>
% }

@@ layouts/default.html.ep
<!DOCTYPE html>
<html>
<head><title>How about CSRF?</title></head>
<body><%= content %></body>
</html>


テンプレートのCSRF-tokenのinputタグの部分を削除するなどいじってみると挙動が変わって面白いですよ!