File Coverage

blib/lib/Mojolicious/Plugin/WithCSRFProtection.pm
Criterion Covered Total %
statement 21 21 100.0
branch 4 4 100.0
condition 6 6 100.0
subroutine 5 5 100.0
pod 1 1 100.0
total 37 37 100.0


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::WithCSRFProtection;
2              
3             # ABSTRACT: Mojolicious plugin providing CSRF protection at the routing level
4              
5 2     2   1311 use Mojo::Base 'Mojolicious::Plugin';
  2         2  
  2         12  
6              
7             our $VERSION = '1.00';
8              
9             #pod =head1 SYNOPSIS
10             #pod
11             #pod # in a lite application
12             #pod post '/some-url' => ( with_csrf_protection => 1 ) => sub { ... };
13             #pod
14             #pod # in a full application
15             #pod $app->routes->post('/some-url')
16             #pod ->with_csrf_protection
17             #pod ->to(...);
18             #pod
19             #pod =head1 DESCRIPTION
20             #pod
21             #pod This Mojolicious plugin provides a routing condition (called
22             #pod C) and routing shortcut to add that condition (also called
23             #pod C) that can be used to protect against cross site request
24             #pod forgery.
25             #pod
26             #pod Adding the condition to the route checks a valid CSRF token was passed, either
27             #pod in the C HTTP header or in the C parameter.
28             #pod
29             #pod Failing the CSRF check causes a 403 error and the C template to be
30             #pod rendered, or if no such template is found a simple error string to be
31             #pod output. This behavior is unlike most conditions that can be applied to
32             #pod Mojolicious routes that normally just cause the route matching to fail and
33             #pod alternative subsequent routes to be evaluated, but immediately returning an
34             #pod error response makes sense for a failed CSRF check. The actual error rendering
35             #pod is performed by the C helper that this plugin installs, and if
36             #pod you want different error output you should override that helper.
37             #pod
38             #pod =cut
39              
40             sub register {
41 2     2 1 61 my ( $self, $app ) = @_;
42              
43 2         10 my $routes = $app->routes;
44              
45             $app->helper(
46             'reply.bad_csrf' => sub {
47 9     9   785 my ($c) = @_;
48 9         20 $c->res->code(403);
49 9 100       86 $c->render_maybe('bad_csrf')
50             or $c->render( text => 'Failed CSRF check' );
51 9         9462 return;
52             }
53 2         24 );
54              
55             $routes->add_condition(
56             with_csrf_protection => sub {
57 15     15   85731 my ( $route, $c ) = @_;
58              
59 15   100     39 my $csrf = $c->req->headers->header('X-CSRF-Token')
60             || $c->param('csrf_token');
61              
62 15 100 100     2057 unless ( $csrf && $csrf eq $c->csrf_token ) {
63 9         1758 $c->reply->bad_csrf;
64 9         28 return;
65             }
66              
67 6         1601 return 1;
68             }
69 2         58 );
70              
71             $routes->add_shortcut(
72             with_csrf_protection => sub {
73 1     1   565 my ($route) = @_;
74 1         3 return $route->over( with_csrf_protection => 1 );
75             }
76 2         34 );
77              
78 2         23 return;
79             }
80              
81             1;
82              
83             __END__