diff --git a/Koha/ContentSecurityPolicy.pm b/Koha/ContentSecurityPolicy.pm
index d112b58615..306af6f4fb 100644
--- a/Koha/ContentSecurityPolicy.pm
+++ b/Koha/ContentSecurityPolicy.pm
@@ -88,11 +88,10 @@ sub header_name {
my $conf_csp = $self->{config}->get('content_security_policy');
- Koha::Exceptions::Config::MissingEntry->throw( error => 'Missing request content_security_policy csp_header_value' )
- unless exists $conf_csp->{$interface}->{csp_mode};
-
- return 'Content-Security-Policy-Report-Only' if $conf_csp->{$interface}->{csp_mode} eq 'report-only';
- return 'Content-Security-Policy' if $conf_csp->{$interface}->{csp_mode} eq 'enabled';
+ if ( $conf_csp && $conf_csp->{$interface} && $conf_csp->{$interface}->{csp_mode} ) {
+ return 'Content-Security-Policy-Report-Only' if $conf_csp->{$interface}->{csp_mode} eq 'report-only';
+ return 'Content-Security-Policy' if $conf_csp->{$interface}->{csp_mode} eq 'enabled';
+ }
Koha::Exceptions::Config::MissingEntry->throw(
error => 'Content Security Policy is disabled. Header name should only be retrieved when CSP is enabled.' );
@@ -112,8 +111,6 @@ sub header_name {
Returns content_security_policy.[opac|staff].csp_header_value
- Throws Koha::Exceptions::Config::MissingEntry is CSP property "csp_header_value" is missing in KOHA_CONF
-
=cut
sub header_value {
@@ -121,15 +118,29 @@ sub header_value {
my $interface = $args->{interface} || C4::Context->interface;
+ my @default_policy_lines = (
+ q#default-src 'self'#,
+ q# script-src 'self' 'nonce-_CSP_NONCE_'#,
+ q# style-src 'self' 'nonce-_CSP_NONCE_'#,
+ q# style-src-attr 'unsafe-inline'#,
+ q# img-src 'self' data:#,
+ q# font-src 'self'#,
+ q# object-src 'none'#,
+ );
+ my $default_policy = join( ';', @default_policy_lines );
+
my $conf_csp = $self->{config}->get('content_security_policy');
- Koha::Exceptions::Config::MissingEntry->throw( error => 'Missing request content_security_policy csp_header_value' )
- unless exists $conf_csp->{$interface}->{csp_header_value};
+ my $user_policy = $conf_csp->{$interface}->{csp_header_value};
- my $csp_header_value = $conf_csp->{$interface}->{csp_header_value};
+ my $csp_policy = ($user_policy) ? $user_policy : $default_policy;
+
+ my $csp_header_value = $csp_policy;
my $csp_nonce = $self->get_nonce;
- $csp_header_value =~ s/_CSP_NONCE_/$csp_nonce/g;
+ if ($csp_nonce) {
+ $csp_header_value =~ s/_CSP_NONCE_/$csp_nonce/g;
+ }
return $csp_header_value;
}
diff --git a/debian/templates/koha-conf-site.xml.in b/debian/templates/koha-conf-site.xml.in
index 9b09b89ecf..88845b246d 100644
--- a/debian/templates/koha-conf-site.xml.in
+++ b/debian/templates/koha-conf-site.xml.in
@@ -514,21 +514,39 @@ __END_SRU_PUBLICSERVER__
csp_header_value: The CSP policy directives. Special placeholders:
- _CSP_NONCE_: Replaced with a unique nonce for each request
- Recommended workflow:
- 1. Start with report-only mode to identify violations
- 2. Review logs and fix any legitimate violations
- 3. Switch to enabled mode once violations are resolved
+ NOTE: Koha comes with a hard-coded csp_header_value. You only need to define your own
+ csp_header_value if you want or need a different Content-Security-Policy value.
+
+ To enable violation reporting, create your own csp_header_value including
+ 'report-to' pointing to csp-violations and add 'report-uri'.
+
+ NOTE: You must be using HTTPS to receive violation reports.
- To enable violation reporting, add report-to to your policy pointing to csp-violations.
Example with reporting:
- default-src 'self'; script-src 'self' 'nonce-_CSP_NONCE_'; style-src 'self' 'nonce-_CSP_NONCE_'; style-src-attr 'unsafe-inline'; img-src 'self' data:; font-src 'self'; object-src 'none'; report-uri /api/v1/public/csp-reports; report-to csp-violations
+
+
+ report-only
+ default-src 'self'; script-src 'self' 'nonce-_CSP_NONCE_'; style-src 'self' 'nonce-_CSP_NONCE_'; style-src-attr 'unsafe-inline'; img-src 'self' data:; font-src 'self'; object-src 'none'; report-uri /api/v1/public/csp-reports; report-to csp-violations
+
+
+ report-only
+ default-src 'self'; script-src 'self' 'nonce-_CSP_NONCE_'; style-src 'self' 'nonce-_CSP_NONCE_'; style-src-attr 'unsafe-inline'; img-src 'self' data:; font-src 'self'; object-src 'none'; report-uri /api/v1/public/csp-reports; report-to csp-violations
+
+
Reports are logged via Koha's logging system. Configure log4perl to capture them:
- log4perl.logger.api.csp = WARN, CSP
- log4perl.appender.CSP = Log::Log4perl::Appender::File
- log4perl.appender.CSP.filename = /var/log/koha/__KOHASITE__/csp-violations.log
- log4perl.appender.CSP.layout = PatternLayout
- log4perl.appender.CSP.layout.ConversionPattern = [%d] %m%n
+ log4perl.logger.plack-csp = WARN, PLACKCSP
+ log4perl.appender.PLACKCSP=Log::Log4perl::Appender::File
+ log4perl.appender.PLACKCSP.filename=/var/log/koha//plack-csp-violations.log
+ log4perl.appender.PLACKCSP.mode=append
+ log4perl.appender.PLACKCSP.layout=PatternLayout
+ log4perl.appender.PLACKCSP.layout.ConversionPattern=[%d] %m%n
+ log4perl.appender.PLACKCSP.utf8=1
+
+ Recommended workflow:
+ 1. Start with report-only mode to identify violations
+ 2. Review logs and fix any legitimate violations (by fixing the code or by modifying your csp_header_value)
+ 3. Switch to enabled mode once violations are resolved
-->
diff --git a/etc/koha-conf.xml b/etc/koha-conf.xml
index 97108498fd..5ef7295b56 100644
--- a/etc/koha-conf.xml
+++ b/etc/koha-conf.xml
@@ -325,21 +325,39 @@
csp_header_value: The CSP policy directives. Special placeholders:
- _CSP_NONCE_: Replaced with a unique nonce for each request
- Recommended workflow:
- 1. Start with report-only mode to identify violations
- 2. Review logs and fix any legitimate violations
- 3. Switch to enabled mode once violations are resolved
+ NOTE: Koha comes with a hard-coded csp_header_value. You only need to define your own
+ csp_header_value if you want or need a different Content-Security-Policy value.
+
+ To enable violation reporting, create your own csp_header_value including
+ 'report-to' pointing to csp-violations and add 'report-uri'.
+
+ NOTE: You must be using HTTPS to receive violation reports.
- To enable violation reporting, add report-to to your policy pointing csp-violations.
Example with reporting:
- default-src 'self'; script-src 'self' 'nonce-_CSP_NONCE_'; style-src 'self' 'nonce-_CSP_NONCE_'; style-src-attr 'unsafe-inline'; img-src 'self' data:; font-src 'self'; object-src 'none'; report-uri /api/v1/public/csp-reports; report-to csp-violations
+
+
+ report-only
+ default-src 'self'; script-src 'self' 'nonce-_CSP_NONCE_'; style-src 'self' 'nonce-_CSP_NONCE_'; style-src-attr 'unsafe-inline'; img-src 'self' data:; font-src 'self'; object-src 'none'; report-uri /api/v1/public/csp-reports; report-to csp-violations
+
+
+ report-only
+ default-src 'self'; script-src 'self' 'nonce-_CSP_NONCE_'; style-src 'self' 'nonce-_CSP_NONCE_'; style-src-attr 'unsafe-inline'; img-src 'self' data:; font-src 'self'; object-src 'none'; report-uri /api/v1/public/csp-reports; report-to csp-violations
+
+
Reports are logged via Koha's logging system. Configure log4perl to capture them:
- log4perl.logger.api.csp = WARN, CSP
- log4perl.appender.CSP = Log::Log4perl::Appender::File
- log4perl.appender.CSP.filename = /var/log/koha/csp-violations.log
- log4perl.appender.CSP.layout = PatternLayout
- log4perl.appender.CSP.layout.ConversionPattern = [%d] %m%n
+ log4perl.logger.plack-csp = WARN, PLACKCSP
+ log4perl.appender.PLACKCSP=Log::Log4perl::Appender::File
+ log4perl.appender.PLACKCSP.filename=/var/log/koha//plack-csp-violations.log
+ log4perl.appender.PLACKCSP.mode=append
+ log4perl.appender.PLACKCSP.layout=PatternLayout
+ log4perl.appender.PLACKCSP.layout.ConversionPattern=[%d] %m%n
+ log4perl.appender.PLACKCSP.utf8=1
+
+ Recommended workflow:
+ 1. Start with report-only mode to identify violations
+ 2. Review logs and fix any legitimate violations (by fixing the code or by modifying your csp_header_value)
+ 3. Switch to enabled mode once violations are resolved
-->
diff --git a/t/Koha/ContentSecurityPolicy.t b/t/Koha/ContentSecurityPolicy.t
index b24f26e9ac..ef7ce71589 100755
--- a/t/Koha/ContentSecurityPolicy.t
+++ b/t/Koha/ContentSecurityPolicy.t
@@ -117,22 +117,13 @@ subtest 'header_name tests' => sub {
};
subtest 'header_value tests' => sub {
- plan tests => 6;
+ plan tests => 3;
t::lib::Mocks::mock_config( $conf_csp_section, {} );
C4::Context->interface('opac');
my $csp = Koha::ContentSecurityPolicy->new;
- throws_ok { $csp->header_value } 'Koha::Exceptions::Config::MissingEntry',
- 'Exception thrown when missing csp_header_value';
-
- t::lib::Mocks::mock_config( $conf_csp_section, { opac => {} } );
- throws_ok { $csp->header_value } 'Koha::Exceptions::Config::MissingEntry',
- 'Exception thrown when missing csp_header_value';
-
- t::lib::Mocks::mock_config( $conf_csp_section, { opac => { csp_header_value => '' } } );
- is( $csp->header_value, '', 'Even an empty csp_header_value is retrieved form koha-conf.xml' );
t::lib::Mocks::mock_config( $conf_csp_section, { opac => { csp_header_value => 'some value' } } );
is( $csp->header_value, 'some value', 'csp_header_value is retrieved from koha-conf.xml' );