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   14857 use v5.14;
  8         28  
6              
7 8     8   44 use warnings;
  8         17  
  8         248  
8              
9 8     8   41 use parent qw( Plack::Middleware );
  8         17  
  8         46  
10              
11 8     8   3221 use Hash::Match;
  8         187968  
  8         301  
12 8     8   57 use HTTP::Status qw( HTTP_BAD_REQUEST );
  8         19  
  8         516  
13 8     8   54 use Ref::Util qw/ is_plain_arrayref is_plain_hashref /;
  8         31  
  8         372  
14              
15 8     8   2788 use Plack::Response;
  8         55040  
  8         295  
16 8     8   57 use Plack::Util::Accessor qw( rules handler status );
  8         18  
  8         52  
17              
18             # RECOMMEND PREREQ: Ref::Util::XS
19              
20             our $VERSION = 'v0.11.0';
21              
22              
23             sub prepare_app {
24 8     8 1 864 my ($self) = @_;
25              
26 8 50       51 if (my $rules = $self->rules) {
27              
28 8 100 100     466 if ( is_plain_arrayref($rules) || is_plain_hashref($rules) ) {
29 6         33 $self->rules( Hash::Match->new( rules => $rules ) );
30             }
31              
32             }
33              
34 8 100       1677 unless ( $self->status ) {
35 7         65 $self->status( HTTP_BAD_REQUEST );
36             }
37              
38 8 100       63 unless ( $self->handler ) {
39             $self->handler(
40             sub {
41 88     88   10945 my ($env) = @_;
42 88         227 my $status = $self->status;
43 88 100       473 if ( my $logger = $env->{'psgix.logger'} ) {
44 1         9 $logger->({
45             level => "warn",
46             message => __PACKAGE__
47             . " Blocked $env->{REMOTE_ADDR} $env->{REQUEST_METHOD} $env->{REQUEST_URI} HTTP $status"
48             });
49             }
50 88         760 my $res = Plack::Response->new($status, [ 'Content-Type' => 'text/plain' ], [ "Bad Request" ] );
51 88         6554 return $res->finalize;
52              
53             }
54 7         75 );
55             }
56              
57             }
58              
59             sub call {
60 109     109 1 675922 my ( $self, $env ) = @_;
61 109 50       348 if (my $rules = $self->rules) {
62 109 100       812 return $self->handler()->( $env ) if $rules->($env);
63             }
64 18         744 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.11.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 years.
151              
152             If you need this module on Perl v5.10, please use one of the v0.8.x
153             versions of this module. Significant bug or security fixes may be
154             backported to those versions.
155              
156             =head1 SEE ALSO
157              
158             L<Hash::Match>
159              
160             L<Plack>
161              
162             L<PSGI>
163              
164             =head1 SOURCE
165              
166             The development version is on github at L<https://github.com/robrwo/Plack-Middleware-Security-Simple>
167             and may be cloned from L<git://github.com/robrwo/Plack-Middleware-Security-Simple.git>
168              
169             =head1 BUGS
170              
171             Please report any bugs or feature requests on the bugtracker website
172             L<https://github.com/robrwo/Plack-Middleware-Security-Simple/issues>
173              
174             When submitting a bug or request, please include a test-file or a
175             patch to an existing test-file that illustrates the bug or desired
176             feature.
177              
178             =head1 AUTHOR
179              
180             Robert Rothenberg <rrwo@cpan.org>
181              
182             =head1 COPYRIGHT AND LICENSE
183              
184             This software is Copyright (c) 2014,2018-2023 by Robert Rothenberg.
185              
186             This is free software, licensed under:
187              
188             The Artistic License 2.0 (GPL Compatible)
189              
190             =cut