App-WebPerimeterScan
view release on metacpan or search on metacpan
lib/App/WebPerimeterScan/Checks.pm view on Meta::CPAN
# Entry: $page from check_page.
# Exit: $page.
# Side effects: may add nosniff-missing, referrer-policy-missing,
# permissions-policy-missing.
sub _check_simple_headers :Private
{
my ($page) = @_;
my $headers = $page->{headers};
my $xcto = _last($headers, 'x-content-type-options');
_page_flag($page, 'nosniff-missing', vars => { present => defined $xcto ? 'yes' : 'no', value => $xcto })
unless defined $xcto && $xcto =~ /nosniff/i;
_page_flag($page, 'referrer-policy-missing') unless defined _last($headers, 'referrer-policy');
# Feature-Policy is the old name and still counts.
_page_flag($page, 'permissions-policy-missing')
unless grep { defined _last($headers, $_) } qw(permissions-policy feature-policy);
return $page;
lib/App/WebPerimeterScan/HTTP.pm view on Meta::CPAN
host => lc $target->{host},
port => $target->{port},
scheme => $target->{scheme},
status => $parsed->{status},
reason => $parsed->{reason},
http_version => $parsed->{http_version},
headers => $headers,
set_cookie => $headers->{'set-cookie'} || [],
body => $body,
truncated => $truncated,
content_type => $headers->{'content-type'} ? $headers->{'content-type'}[0] : '',
# The header block as it arrived, for reports that have to show it.
raw_headers => $head,
};
}
# _request_text
# Purpose: the bytes of one HTTP/1.1 request.
# Entry: $method matches $METHOD_RE; $extra is an arrayref or undef.
# Exit: the request string, ending in a blank line.
# Side effects: none.
ok($ids{'referrer-policy-missing'}, 'missing Referrer-Policy reported');
ok($ids{'permissions-policy-missing'}, 'missing Permissions-Policy reported');
is($findings->count, 6, 'six header findings on a bare HTTPS page');
}
{
my $findings = run_page(res => response(
headers => {
'strict-transport-security' => ['max-age=31536000; includeSubDomains'],
'content-security-policy' => ["default-src 'self'; frame-ancestors 'none'"],
'x-content-type-options' => ['nosniff'],
'referrer-policy' => ['strict-origin-when-cross-origin'],
'permissions-policy' => ['camera=()'],
'server' => ['nginx'],
},
body => '<html><head><title>ok</title></head><body>hello</body></html>',
));
is($findings->count, 0, 'hardened page produces no findings');
}
# The record itself: duplicates preserved, failed requests not recorded.
my $scanner = App::WebPerimeterScan->new;
my $record = $scanner->_record_response(
'https://example.org/', 'GET',
{
status => 200,
http_version => 'HTTP/1.1',
reason => 'OK',
headers => {
'set-cookie' => [ 'a=1', 'b=2' ],
'content-type' => ['text/html'],
},
raw_headers => 'HTTP/1.1 200 OK',
},
);
is($record->{status}, 200, 'response record keeps the status');
is_deeply($record->{headers}{'set-cookie'}, [ 'a=1', 'b=2' ],
'repeated headers preserved, not collapsed');
is($record->{raw}, 'HTTP/1.1 200 OK', 'raw header block is kept verbatim');
is($scanner->_record_response('https://example.org/', 'GET', { error => 'connect failed' }),
undef, 'a failed request is not recorded');
( run in 1.100 second using v1.01-cache-2.11-cpan-99fa8243a42 )