Skip to content

Commit

Permalink
Merge pull request #14 from mtths/master
Browse files Browse the repository at this point in the history
optionally allow signed cookies, escape token injected into html
  • Loading branch information
chizmw committed Oct 8, 2014
2 parents 26e4cf0 + 6b3e678 commit 6e3172a
Showing 1 changed file with 40 additions and 0 deletions.
40 changes: 40 additions & 0 deletions lib/Plack/Middleware/XSRFBlock.pm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use warnings;
use parent 'Plack::Middleware';

use Digest::HMAC_SHA1 'hmac_sha1_hex';
use HTML::Escape qw(escape_html);
use HTML::Parser;
use HTTP::Status qw(:constants);

Expand All @@ -22,6 +23,7 @@ use Plack::Util::Accessor qw(
token_per_request
parameter_name
header_name
secret
_token_generator
);

Expand Down Expand Up @@ -53,6 +55,13 @@ sub prepare_app {
my $data = rand() . $$ . {} . time;
my $key = "@INC";
my $digest = hmac_sha1_hex($data, $key);

if (defined $self->secret) {
my $sig = hmac_sha1_hex($digest, $self->secret);
$digest .= "--$sig";
}

return $digest;
});
}

Expand Down Expand Up @@ -105,6 +114,10 @@ sub call {
# reject if the form value and the token don't match
return $self->xsrf_detected( { env => $env, msg => 'invalid token' } )
if $val ne $cookie_value;

return $self->xsrf_detected( { env => $env,
msg => 'invalid signature' } )
if $self->invalid_signature($val);
}

return Plack::Util::response_cb($self->app->($env), sub {
Expand Down Expand Up @@ -144,6 +157,9 @@ sub call {

return $res unless $self->inject_form_input;

# escape token (someone might have tampered with the cookie)
$token = escape_html($token);

# let's inject our field+token into the form
my @out;
my $http_host = $request->uri->host;
Expand Down Expand Up @@ -241,6 +257,20 @@ sub call {
});
}

sub invalid_signature {
my ($self, $value) = @_;

# we dont use signed cookies
return if !defined $self->secret;

# cookie isn't signed
my ($token, $signature) = split /--/, $value;
return 1 if !defined $signature || $signature eq '';

# signature doesn't validate
return hmac_sha1_hex($token, $self->secret) ne $signature;
}

sub xsrf_detected {
my $self = shift;
my $args = shift;
Expand Down Expand Up @@ -317,6 +347,7 @@ You may also over-ride any, or all of these values:
meta_tag => undef,
inject_form_input => 1,
header_name => undef,
secret => undef,
blocked => sub {
return [ $status, $headers, $body ]
},
Expand Down Expand Up @@ -385,6 +416,10 @@ If this is set, use the value as the name of the response heaer that the token
can be sent in. This is useful for non-browser based submissions; e.g.
Javascript AJAX requests.
=item secret (default: undef)
Signs the cookie with supplied secret (if set).
=item blocked (default: undef)
If this is set it should be a PSGI application that is returned instead of the
Expand Down Expand Up @@ -422,6 +457,11 @@ PSGI-XSRF-Token]
The cookie token and form value were both submitted correctly but the values
do not match.
=item invalid signature
The cookies signature is invalid, indicating it was tampered with on the way
to the browser.
=back
=head1 EXPLANATION
Expand Down

0 comments on commit 6e3172a

Please sign in to comment.