Amon2-Plugin-Web-CpanelJSON
view release on metacpan or search on metacpan
Changes
LICENSE
META.json
README.md
cpanfile
lib/Amon2/Plugin/Web/CpanelJSON.pm
minil.toml
t/00_compile.t
t/01_render_json.t
t/10-config/json.t
t/10-config/json_escape_filter.t
t/10-config/name.t
t/10-config/secure_headers.t
t/10-config/status_code_field.t
t/10-config/unbless_object.t
t/20-compatibility/007_json.t
t/20-compatibility/007_json_default_encoding.t
t/20-compatibility/007_json_hijacking.t
t/20-compatibility/007_json_keysort.t
t/20-compatibility/007_json_x_api_status.t
t/30_integration/JSON-UnblessObject/unbless_object.t
content_security_policy => "default-src 'none'",
strict_transport_security => 'max-age=631138519',
x_content_type_options => 'nosniff',
x_download_options => undef,
x_frame_options => 'DENY',
x_permitted_cross_domain_policies => 'none',
x_xss_protection => '1; mode=block',
referrer_policy => 'no-referrer',
```
- json\_escape\_filter
Escapes JSON to prevent XSS. Default is as follows:
```perl
'+' => '\\u002b',
'<' => '\\u003c',
'>' => '\\u003e',
```
- name
lib/Amon2/Plugin/Web/CpanelJSON.pm view on Meta::CPAN
content_security_policy => "default-src 'none'",
strict_transport_security => 'max-age=631138519',
x_content_type_options => 'nosniff',
x_download_options => undef,
x_frame_options => 'DENY',
x_permitted_cross_domain_policies => 'none',
x_xss_protection => '1; mode=block',
referrer_policy => 'no-referrer',
},
json_escape_filter => {
# Ref: https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html
# Ref: (Japanese) http://www.atmarkit.co.jp/fcoding/articles/webapp/05/webapp05a.html
'+' => '\\u002b', # do not eval as UTF-7
'<' => '\\u003c', # do not eval as HTML
'>' => '\\u003e', # ditto.
},
# JSON config
json => {
ascii => !!1, # for security
lib/Amon2/Plugin/Web/CpanelJSON.pm view on Meta::CPAN
defence_json_hijacking_for_legacy_browser => !!0,
);
sub init {
my ($class, $c, $conf) = @_;
$conf = do {
$conf ||= {};
for my $key (qw/secure_headers json_escape_filter json/) {
if (exists $conf->{$key} && !defined $conf->{$key}) {
$conf->{$key} = undef;
}
else {
$conf->{$key} = {
%{ $DEFAULT_CONFIG{$key} },
%{ $conf->{$key} || {} },
}
}
}
lib/Amon2/Plugin/Web/CpanelJSON.pm view on Meta::CPAN
sub _generate_json_encoder {
my $conf = shift;
my $json = Cpanel::JSON::XS->new;
if (my $json_args = $conf->{json}) {
for my $key (keys %{$json_args}) {
$json->$key($json_args->{$key})
}
}
my $escape_filter = $conf->{json_escape_filter} || {};
my $escape_target = '';
for my $key (keys %{$escape_filter}) {
if ($escape_filter->{$key}) {
$escape_target .= $key
}
}
return sub {
my ($data, $spec) = @_;
if (my $unbless_object = $conf->{unbless_object}) {
if (blessed($data)) {
$data = $unbless_object->($data, $spec);
}
}
my $output = $json->encode($data, $spec);
if ($escape_target && $escape_filter) {
$output =~ s!([$escape_target])!$escape_filter->{$1}!g;
}
return $output;
}
}
sub _generate_req_validator {
my $conf = shift;
return sub {
lib/Amon2/Plugin/Web/CpanelJSON.pm view on Meta::CPAN
content_security_policy => "default-src 'none'",
strict_transport_security => 'max-age=631138519',
x_content_type_options => 'nosniff',
x_download_options => undef,
x_frame_options => 'DENY',
x_permitted_cross_domain_policies => 'none',
x_xss_protection => '1; mode=block',
referrer_policy => 'no-referrer',
=item json_escape_filter
Escapes JSON to prevent XSS. Default is as follows:
'+' => '\\u002b',
'<' => '\\u003c',
'>' => '\\u003e',
=item name
Name of method. Default: 'render_json'
t/10-config/json_escape_filter.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use Cpanel::JSON::XS qw(decode_json);
{
package MyApp::Web::Off;
use parent qw(Amon2 Amon2::Web);
__PACKAGE__->load_plugins('Web::CpanelJSON', { json_escape_filter => undef });
sub encoding { 'utf-8' }
}
{
package MyApp::Web::PartialOff;
use parent qw(Amon2 Amon2::Web);
__PACKAGE__->load_plugins(
'Web::CpanelJSON', {
json_escape_filter => {
'+' => undef,
'<' => '\\u003c',
'>' => '\\u003e',
}
}
);
sub encoding { 'utf-8' }
}
{
package MyApp::Web::Default;
use parent qw(Amon2 Amon2::Web);
__PACKAGE__->load_plugins('Web::CpanelJSON');
sub encoding { 'utf-8' }
}
my $src = { key => '<script>alert("HELLO"+"WORLD")</script>' };
subtest 'json_escape default is on' => sub {
my $c = MyApp::Web::Default->new(request => Amon2::Web::Request->new({}));
my $res = $c->render_json($src);
is $res->code, 200;
is $res->content, '{"key":"\u003cscript\u003ealert(\"HELLO\"\u002b\"WORLD\")\u003c/script\u003e"}';
is_deeply decode_json($res->content), $src;
};
subtest 'json_escape off' => sub {
my $c = MyApp::Web::Off->new(request => Amon2::Web::Request->new({}));
my $res = $c->render_json($src);
is $res->code, 200;
is $res->content, '{"key":"<script>alert(\"HELLO\"+\"WORLD\")</script>"}';
is_deeply decode_json($res->content), $src;
};
subtest 'json_escape partial off' => sub {
my $c = MyApp::Web::PartialOff->new(request => Amon2::Web::Request->new({}));
my $res = $c->render_json($src);
is $res->code, 200;
is $res->content, '{"key":"\u003cscript\u003ealert(\"HELLO\"+\"WORLD\")\u003c/script\u003e"}';
is_deeply decode_json($res->content), $src;
};
done_testing;
( run in 0.885 second using v1.01-cache-2.11-cpan-c21f80fb71c )