File Coverage

blib/lib/Plack/Middleware/Security/Simple.pm
Criterion Covered Total %
statement 41 41 100.0
branch 12 14 85.7
condition 3 3 100.0
subroutine 11 11 100.0
pod 2 2 100.0
total 69 71 97.1


line stmt bran cond sub pod time code
1             package Plack::Middleware::Security::Simple;
2              
3             # ABSTRACT: A simple security filter for Plack
4              
5 8     8   14893 use v5.14;
  8         32  
6              
7 8     8   49 use warnings;
  8         15  
  8         241  
8              
9 8     8   47 use parent qw( Plack::Middleware );
  8         27  
  8         43  
10              
11 8     8   3278 use Hash::Match;
  8         188646  
  8         286  
12 8     8   72 use HTTP::Status qw( HTTP_BAD_REQUEST );
  8         16  
  8         498  
13 8     8   53 use Ref::Util qw/ is_plain_arrayref is_plain_hashref /;
  8         25  
  8         376  
14              
15 8     8   2741 use Plack::Response;
  8         54537  
  8         303  
16 8     8   64 use Plack::Util::Accessor qw( rules handler status );
  8         22  
  8         68  
17              
18             # RECOMMEND PREREQ: Ref::Util::XS
19              
20             our $VERSION = 'v0.10.1';
21              
22              
23             sub prepare_app {
24 8     8 1 860 my ($self) = @_;
25              
26 8 50       54 if (my $rules = $self->rules) {
27              
28 8 100 100     524 if ( is_plain_arrayref($rules) || is_plain_hashref($rules) ) {
29 6         29 $self->rules( Hash::Match->new( rules => $rules ) );
30             }
31              
32             }
33              
34 8 100       1768 unless ( $self->status ) {
35 7         63 $self->status( HTTP_BAD_REQUEST );
36             }
37              
38 8 100       70 unless ( $self->handler ) {
39             $self->handler(
40             sub {
41 84     84   9826 my ($env) = @_;
42 84         217 my $status = $self->status;
43 84 100       433 if ( my $logger = $env->{'psgix.logger'} ) {
44 1         7 $logger->({
45             level => "warn",
46             message => __PACKAGE__
47             . " Blocked $env->{REMOTE_ADDR} $env->{REQUEST_METHOD} $env->{REQUEST_URI} HTTP $status"
48             });
49             }
50 84         761 my $res = Plack::Response->new($status, [ 'Content-Type' => 'text/plain' ], [ "Bad Request" ] );
51 84         6718 return $res->finalize;
52              
53             }
54 7         69 );
55             }
56              
57             }
58              
59             sub call {
60 105     105 1 659459 my ( $self, $env ) = @_;
61 105 50       331 if (my $rules = $self->rules) {
62 105 100       795 return $self->handler()->( $env ) if $rules->($env);
63             }
64 18         773 return $self->app->($env);
65             }
66              
67              
68             1;
69              
70             __END__
71              
72             =pod
73              
74             =encoding UTF-8
75              
76             =head1 NAME
77              
78             Plack::Middleware::Security::Simple - A simple security filter for Plack
79              
80             =head1 VERSION
81              
82             version v0.10.1
83              
84             =head1 SYNOPSIS
85              
86             use Plack::Builder;
87              
88             builder {
89              
90             enable "Security::Simple",
91             rules => [
92             PATH_INFO => qr{^/cgi-bin/},
93             PATH_INFO => qr{\.(php|asp)$},
94             HTTP_USER_AGENT => qr{BadRobot},
95             ];
96              
97             ...
98              
99             };
100              
101             =head1 DESCRIPTION
102              
103             This module provides a simple security filter for PSGI-based
104             applications, so that you can filter out obvious exploit-seeking
105             scripts.
106              
107             Note that as an alternative, you may want to consider using something like
108             L<modsecurity|https://modsecurity.org/> as a filter in a reverse proxy.
109              
110             =head1 ATTRIBUTES
111              
112             =head2 rules
113              
114             This is a set of rules. It can be a an array-reference or
115             L<Hash::Match> object containing matches against keys in the Plack
116             environment.
117              
118             It can also be a code reference for a subroutine that takes the Plack
119             environment as an argument and returns a true value if there is a
120             match.
121              
122             See L<Plack::Middleware::Security::Common> for a set of common rules.
123              
124             =head2 handler
125              
126             This is a function that is called when a match is found.
127              
128             It takes the Plack environment as an argument, and returns a
129             L<Plack::Response>, or throws an exception for
130             L<Plack::Middleware::HTTPExceptions>.
131              
132             The default handler will log a warning to the C<psgix.logger>, and
133             return a HTTP 400 (Bad Request) response.
134              
135             The message is of the form
136              
137             Plack::Middleware::Security::Simple Blocked $ip $method $path_query HTTP $status
138              
139             This can be used if you are writing L<fail2ban> filters.
140              
141             =head2 status
142              
143             This is the HTTP status code that the default L</handler> will return
144             when a resource is blocked. It defaults to 400 (Bad Request).
145              
146             =head1 SUPPORT FOR OLDER PERL VERSIONS
147              
148             Since v0.9.0, the this module requires Perl v5.14 or later.
149              
150             If you need this module on Perl v5.10, please use one of the v0.8.x
151             versions of this module. Significant bug or security fixes may be
152             backported to those versions.
153              
154             =head1 SEE ALSO
155              
156             L<Hash::Match>
157              
158             L<Plack>
159              
160             L<PSGI>
161              
162             =head1 SOURCE
163              
164             The development version is on github at L<https://github.com/robrwo/Plack-Middleware-Security-Simple>
165             and may be cloned from L<git://github.com/robrwo/Plack-Middleware-Security-Simple.git>
166              
167             =head1 BUGS
168              
169             Please report any bugs or feature requests on the bugtracker website
170             L<https://github.com/robrwo/Plack-Middleware-Security-Simple/issues>
171              
172             When submitting a bug or request, please include a test-file or a
173             patch to an existing test-file that illustrates the bug or desired
174             feature.
175              
176             =head1 AUTHOR
177              
178             Robert Rothenberg <rrwo@cpan.org>
179              
180             =head1 COPYRIGHT AND LICENSE
181              
182             This software is Copyright (c) 2014,2018-2023 by Robert Rothenberg.
183              
184             This is free software, licensed under:
185              
186             The Artistic License 2.0 (GPL Compatible)
187              
188             =cut