Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ap/plack-middleware-signedcookies
accept only server-minted cookies
https://github.com/ap/plack-middleware-signedcookies
perl plack psgi
Last synced: 10 days ago
JSON representation
accept only server-minted cookies
- Host: GitHub
- URL: https://github.com/ap/plack-middleware-signedcookies
- Owner: ap
- Created: 2014-12-17T21:39:20.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2023-02-05T10:54:12.000Z (almost 2 years ago)
- Last Synced: 2024-11-06T03:03:57.327Z (about 2 months ago)
- Topics: perl, plack, psgi
- Language: Perl
- Homepage: https://metacpan.org/release/Plack-Middleware-SignedCookies
- Size: 29.3 KB
- Stars: 0
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.pod
- Changelog: Changes
Awesome Lists containing this project
README
use 5.006; use strict; use warnings;
package Plack::Middleware::SignedCookies;
our $VERSION = '1.204';
BEGIN { require Plack::Middleware; our @ISA = 'Plack::Middleware' }
use Plack::Util ();
use Plack::Util::Accessor qw( secret secure httponly );
use Digest::SHA ();sub _hmac { y{+/}{-~}, return $_ for &Digest::SHA::hmac_sha256_base64 }
my $length = length _hmac 'something', 'something';
sub call {
my ( $self, $env ) = ( shift, @_ );my $secret = $self->secret;
my $orig = delete $env->{'HTTP_COOKIE'};
$env->{'signedcookies.orig'} = $orig if defined $orig;my $cookie =
join '; ',
grep { s/[ \t]*=[ \t]*/=/; s/[ \t]*([-~A-Za-z0-9]{$length})\z//o and $1 eq _hmac $_, $secret }
map { defined && /\A[ \t]*(.*[^ \t])/s ? split /[ \t]*;[ \t]*/, "$1" : () }
$orig;$env->{'HTTP_COOKIE'} = $cookie if '' ne $cookie;
return Plack::Util::response_cb( $self->app->( $env ), sub {
my $do_sign;
for ( @{ $_[0][1] } ) {
if ( $do_sign ) {
my $flags = s/(;.*)//s ? $1 : '';
s/\A[ \t]+//, s/[ \t]+\z//, s/[ \t]*=[ \t]*|\z/=/; # normalise
$_ .= ' ' . _hmac( $_, $secret ) . $flags;
$_ .= '; secure' if $self->secure and $flags !~ /;[ \t]* secure [ \t]* (?![^;])/ix;
$_ .= '; HTTPonly' if $self->httponly and $flags !~ /;[ \t]* httponly [ \t]* (?![^;])/ix;
}
$do_sign = defined $do_sign ? undef : 'set-cookie' eq lc;
}
} );
}sub prepare_app {
my $self = shift;
defined $self->httponly or $self->httponly( 1 );
defined $self->secret or $self->secret ( join '', map { chr int rand 256 } 1..17 );
}1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Plack::Middleware::SignedCookies - accept only server-minted cookies
=head1 SYNOPSIS
# in app.psgi
use Plack::Builder;
builder {
enable 'SignedCookies', secret => 's333333333kr1t!!!!1!!';
$app;
};=head1 DESCRIPTION
This middleware modifies C headers in the request and C headers in the response.
It appends a HMAC digest to outgoing cookies and removes and verifies it from incoming cookies.
It rejects incoming cookies that were sent without a valid digest.The incoming C header value remains available in the C key in the PSGI environment.
=head1 CONFIGURATION OPTIONS
=over 4
=item C
The secret to pass to the L HMAC function.
If not provided, a random secret will be generated using PerlEs built-in L function.
=item C
Whether to force the I flag to be set on all cookies,
which instructs the browser to only send them when using an encrypted connection.Defaults to false. B
=item C
Whether to force the I flag to be set on all cookies,
which instructs the browser to not make them available to Javascript on the page.B Provide a defined false value if you wish to override this.
=back
=head1 A NOTE ON EXPIRATION
Several other modules that offer similar functionality will also handle server-side cookie expiration.
This is obviously useful for centralising all cookie policy in one place.However, expiration is quite likely to be a concern at the application level,
if only just to tell a user that they timed out rather than just suddenly forgetting them.
Communicating server-side expiration from the middleware to the application requires a protocol.
No standard protocol exists for this purpose, so it would have to be specific to this middleware.But middlewares are most useful when they can be added or removed without modifying the application.
(Frameworks, in contrast, require tight coupling of the application by definition,
thus making it a reasonable choice to include cookie expiration plus interface in a framework.)
Therefore, it was an explicit design choice for this middleware to omit expiration handling.=head1 SEE ALSO
=over 4
=item *
L6265, I, section 4.1.2.5., I|http://tools.ietf.org/html/rfc6265#section-4.1.2.5>
=item *
L|http://msdn.microsoft.com/en-us/library/ms533046.aspx>
=back
=cut