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   4278416 use v5.14;
  8         34  
6              
7 8     8   62 use warnings;
  8         18  
  8         628  
8              
9 8     8   73 use parent qw( Plack::Middleware );
  8         20  
  8         62  
10              
11 8     8   3689 use Hash::Match;
  8         216248  
  8         412  
12 8     8   64 use HTTP::Status qw( HTTP_BAD_REQUEST );
  8         17  
  8         599  
13 8     8   49 use Ref::Util qw/ is_plain_arrayref is_plain_hashref /;
  8         17  
  8         491  
14              
15 8     8   3369 use Plack::Response;
  8         73543  
  8         326  
16 8     8   60 use Plack::Util::Accessor qw( rules handler status );
  8         18  
  8         77  
17              
18             # RECOMMEND PREREQ: Ref::Util::XS
19              
20             our $VERSION = 'v0.13.0';
21              
22              
23             sub prepare_app {
24 8     8 1 961 my ($self) = @_;
25              
26 8 50       38 if (my $rules = $self->rules) {
27              
28 8 100 100     566 if ( is_plain_arrayref($rules) || is_plain_hashref($rules) ) {
29 6         42 $self->rules( Hash::Match->new( rules => $rules ) );
30             }
31              
32             }
33              
34 8 100       1422 unless ( $self->status ) {
35 7         57 $self->status( HTTP_BAD_REQUEST );
36             }
37              
38 8 100       61 unless ( $self->handler ) {
39             $self->handler(
40             sub {
41 133     133   17284 my ($env) = @_;
42 133         349 my $status = $self->status;
43 133 100       681 if ( my $logger = $env->{'psgix.logger'} ) {
44 1         11 $logger->({
45             level => "warn",
46             message => __PACKAGE__
47             . " Blocked $env->{REMOTE_ADDR} $env->{REQUEST_METHOD} $env->{REQUEST_URI} HTTP $status"
48             });
49             }
50 133         1222 my $res = Plack::Response->new($status, [ 'Content-Type' => 'text/plain' ], [ "Bad Request" ] );
51 133         10245 return $res->finalize;
52              
53             }
54 7         67 );
55             }
56              
57             }
58              
59             sub call {
60 154     154 1 754864 my ( $self, $env ) = @_;
61 154 50       574 if (my $rules = $self->rules) {
62 154 100       1244 return $self->handler()->( $env ) if $rules->($env);
63             }
64 18         860 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.13.0
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             Future releases may only support Perl versions released in the last ten (10) years.
151              
152             =head1 SEE ALSO
153              
154             L<Hash::Match>
155              
156             L<Plack>
157              
158             L<PSGI>
159              
160             =head1 SOURCE
161              
162             The development version is on github at L<https://github.com/robrwo/Plack-Middleware-Security-Simple>
163             and may be cloned from L<git://github.com/robrwo/Plack-Middleware-Security-Simple.git>
164              
165             =head1 BUGS
166              
167             Please report any bugs or feature requests on the bugtracker website
168             L<https://github.com/robrwo/Plack-Middleware-Security-Simple/issues>
169              
170             When submitting a bug or request, please include a test-file or a
171             patch to an existing test-file that illustrates the bug or desired
172             feature.
173              
174             =head2 Reporting Security Vulnerabilities
175              
176             Security issues should not be reported on the bugtracker website. Please see F<SECURITY.md> for instructions how to
177             report security vulnerabilities.
178              
179             =head1 AUTHOR
180              
181             Robert Rothenberg <rrwo@cpan.org>
182              
183             =head1 COPYRIGHT AND LICENSE
184              
185             This software is Copyright (c) 2014,2018-2025 by Robert Rothenberg.
186              
187             This is free software, licensed under:
188              
189             The Artistic License 2.0 (GPL Compatible)
190              
191             =cut