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.

t/checks.t  view on Meta::CPAN

	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');
}

t/report.t  view on Meta::CPAN

# 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 )