View | Details | Raw Unified | Return to bug 38365
Collapse All | Expand All

(-)a/Koha/ContentSecurityPolicy.pm (-11 / +22 lines)
Lines 88-98 sub header_name { Link Here
88
88
89
    my $conf_csp = $self->{config}->get('content_security_policy');
89
    my $conf_csp = $self->{config}->get('content_security_policy');
90
90
91
    Koha::Exceptions::Config::MissingEntry->throw( error => 'Missing request content_security_policy csp_header_value' )
91
    if ( $conf_csp && $conf_csp->{$interface} && $conf_csp->{$interface}->{csp_mode} ) {
92
        unless exists $conf_csp->{$interface}->{csp_mode};
92
        return 'Content-Security-Policy-Report-Only' if $conf_csp->{$interface}->{csp_mode} eq 'report-only';
93
93
        return 'Content-Security-Policy'             if $conf_csp->{$interface}->{csp_mode} eq 'enabled';
94
    return 'Content-Security-Policy-Report-Only' if $conf_csp->{$interface}->{csp_mode} eq 'report-only';
94
    }
95
    return 'Content-Security-Policy'             if $conf_csp->{$interface}->{csp_mode} eq 'enabled';
96
95
97
    Koha::Exceptions::Config::MissingEntry->throw(
96
    Koha::Exceptions::Config::MissingEntry->throw(
98
        error => 'Content Security Policy is disabled. Header name should only be retrieved when CSP is enabled.' );
97
        error => 'Content Security Policy is disabled. Header name should only be retrieved when CSP is enabled.' );
Lines 112-119 sub header_name { Link Here
112
111
113
    Returns content_security_policy.[opac|staff].csp_header_value
112
    Returns content_security_policy.[opac|staff].csp_header_value
114
113
115
    Throws Koha::Exceptions::Config::MissingEntry is CSP property "csp_header_value" is missing in KOHA_CONF
116
117
=cut
114
=cut
118
115
119
sub header_value {
116
sub header_value {
Lines 121-135 sub header_value { Link Here
121
118
122
    my $interface = $args->{interface} || C4::Context->interface;
119
    my $interface = $args->{interface} || C4::Context->interface;
123
120
121
    my @default_policy_lines = (
122
        q#default-src 'self'#,
123
        q# script-src 'self' 'nonce-_CSP_NONCE_'#,
124
        q# style-src 'self' 'nonce-_CSP_NONCE_'#,
125
        q# style-src-attr 'unsafe-inline'#,
126
        q# img-src 'self' data:#,
127
        q# font-src 'self'#,
128
        q# object-src 'none'#,
129
    );
130
    my $default_policy = join( ';', @default_policy_lines );
131
124
    my $conf_csp = $self->{config}->get('content_security_policy');
132
    my $conf_csp = $self->{config}->get('content_security_policy');
125
133
126
    Koha::Exceptions::Config::MissingEntry->throw( error => 'Missing request content_security_policy csp_header_value' )
134
    my $user_policy = $conf_csp->{$interface}->{csp_header_value};
127
        unless exists $conf_csp->{$interface}->{csp_header_value};
135
136
    my $csp_policy = ($user_policy) ? $user_policy : $default_policy;
128
137
129
    my $csp_header_value = $conf_csp->{$interface}->{csp_header_value};
138
    my $csp_header_value = $csp_policy;
130
    my $csp_nonce        = $self->get_nonce;
139
    my $csp_nonce        = $self->get_nonce;
131
140
132
    $csp_header_value =~ s/_CSP_NONCE_/$csp_nonce/g;
141
    if ($csp_nonce) {
142
        $csp_header_value =~ s/_CSP_NONCE_/$csp_nonce/g;
143
    }
133
144
134
    return $csp_header_value;
145
    return $csp_header_value;
135
}
146
}
(-)a/debian/templates/koha-conf-site.xml.in (-11 / +29 lines)
Lines 514-534 __END_SRU_PUBLICSERVER__ Link Here
514
   csp_header_value: The CSP policy directives. Special placeholders:
514
   csp_header_value: The CSP policy directives. Special placeholders:
515
     - _CSP_NONCE_: Replaced with a unique nonce for each request
515
     - _CSP_NONCE_: Replaced with a unique nonce for each request
516
516
517
   Recommended workflow:
517
   NOTE: Koha comes with a hard-coded csp_header_value. You only need to define your own
518
     1. Start with report-only mode to identify violations
518
   csp_header_value if you want or need a different Content-Security-Policy value.
519
     2. Review logs and fix any legitimate violations
519
520
     3. Switch to enabled mode once violations are resolved
520
   To enable violation reporting, create your own csp_header_value including
521
    'report-to' pointing to csp-violations and add 'report-uri'.
522
523
   NOTE: You must be using HTTPS to receive violation reports.
521
524
522
   To enable violation reporting, add report-to to your policy pointing to csp-violations.
523
   Example with reporting:
525
   Example with reporting:
524
     <csp_header_value>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</csp_header_value>
526
   <content_security_policy>
527
      <opac>
528
        <csp_mode>report-only</csp_mode>
529
        <csp_header_value>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</csp_header_value>
530
      </opac>
531
      <intranet>
532
        <csp_mode>report-only</csp_mode>
533
        <csp_header_value>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</csp_header_value>
534
      </intranet>
535
    </content_security_policy>
525
536
526
   Reports are logged via Koha's logging system. Configure log4perl to capture them:
537
   Reports are logged via Koha's logging system. Configure log4perl to capture them:
527
     log4perl.logger.api.csp = WARN, CSP
538
    log4perl.logger.plack-csp = WARN, PLACKCSP
528
     log4perl.appender.CSP = Log::Log4perl::Appender::File
539
    log4perl.appender.PLACKCSP=Log::Log4perl::Appender::File
529
     log4perl.appender.CSP.filename = /var/log/koha/__KOHASITE__/csp-violations.log
540
    log4perl.appender.PLACKCSP.filename=/var/log/koha/<kohasite>/plack-csp-violations.log
530
     log4perl.appender.CSP.layout = PatternLayout
541
    log4perl.appender.PLACKCSP.mode=append
531
     log4perl.appender.CSP.layout.ConversionPattern = [%d] %m%n
542
    log4perl.appender.PLACKCSP.layout=PatternLayout
543
    log4perl.appender.PLACKCSP.layout.ConversionPattern=[%d] %m%n
544
    log4perl.appender.PLACKCSP.utf8=1
545
546
   Recommended workflow:
547
     1. Start with report-only mode to identify violations
548
     2. Review logs and fix any legitimate violations (by fixing the code or by modifying your csp_header_value)
549
     3. Switch to enabled mode once violations are resolved
532
 -->
550
 -->
533
 <content_security_policy>
551
 <content_security_policy>
534
   <opac>
552
   <opac>
(-)a/etc/koha-conf.xml (-11 / +29 lines)
Lines 325-345 Link Here
325
   csp_header_value: The CSP policy directives. Special placeholders:
325
   csp_header_value: The CSP policy directives. Special placeholders:
326
     - _CSP_NONCE_: Replaced with a unique nonce for each request
326
     - _CSP_NONCE_: Replaced with a unique nonce for each request
327
327
328
   Recommended workflow:
328
   NOTE: Koha comes with a hard-coded csp_header_value. You only need to define your own
329
     1. Start with report-only mode to identify violations
329
   csp_header_value if you want or need a different Content-Security-Policy value.
330
     2. Review logs and fix any legitimate violations
330
331
     3. Switch to enabled mode once violations are resolved
331
   To enable violation reporting, create your own csp_header_value including
332
    'report-to' pointing to csp-violations and add 'report-uri'.
333
334
   NOTE: You must be using HTTPS to receive violation reports.
332
335
333
   To enable violation reporting, add report-to to your policy pointing csp-violations.
334
   Example with reporting:
336
   Example with reporting:
335
     <csp_header_value>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</csp_header_value>
337
   <content_security_policy>
338
      <opac>
339
        <csp_mode>report-only</csp_mode>
340
        <csp_header_value>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</csp_header_value>
341
      </opac>
342
      <intranet>
343
        <csp_mode>report-only</csp_mode>
344
        <csp_header_value>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</csp_header_value>
345
      </intranet>
346
    </content_security_policy>
336
347
337
   Reports are logged via Koha's logging system. Configure log4perl to capture them:
348
   Reports are logged via Koha's logging system. Configure log4perl to capture them:
338
     log4perl.logger.api.csp = WARN, CSP
349
        log4perl.logger.plack-csp = WARN, PLACKCSP
339
     log4perl.appender.CSP = Log::Log4perl::Appender::File
350
        log4perl.appender.PLACKCSP=Log::Log4perl::Appender::File
340
     log4perl.appender.CSP.filename = /var/log/koha/csp-violations.log
351
        log4perl.appender.PLACKCSP.filename=/var/log/koha/<kohasite>/plack-csp-violations.log
341
     log4perl.appender.CSP.layout = PatternLayout
352
        log4perl.appender.PLACKCSP.mode=append
342
     log4perl.appender.CSP.layout.ConversionPattern = [%d] %m%n
353
        log4perl.appender.PLACKCSP.layout=PatternLayout
354
        log4perl.appender.PLACKCSP.layout.ConversionPattern=[%d] %m%n
355
        log4perl.appender.PLACKCSP.utf8=1
356
357
   Recommended workflow:
358
     1. Start with report-only mode to identify violations
359
     2. Review logs and fix any legitimate violations (by fixing the code or by modifying your csp_header_value)
360
     3. Switch to enabled mode once violations are resolved
343
 -->
361
 -->
344
 <content_security_policy>
362
 <content_security_policy>
345
   <opac>
363
   <opac>
(-)a/t/Koha/ContentSecurityPolicy.t (-11 / +1 lines)
Lines 117-138 subtest 'header_name tests' => sub { Link Here
117
};
117
};
118
118
119
subtest 'header_value tests' => sub {
119
subtest 'header_value tests' => sub {
120
    plan tests => 6;
120
    plan tests => 3;
121
121
122
    t::lib::Mocks::mock_config( $conf_csp_section, {} );
122
    t::lib::Mocks::mock_config( $conf_csp_section, {} );
123
    C4::Context->interface('opac');
123
    C4::Context->interface('opac');
124
124
125
    my $csp = Koha::ContentSecurityPolicy->new;
125
    my $csp = Koha::ContentSecurityPolicy->new;
126
126
127
    throws_ok { $csp->header_value } 'Koha::Exceptions::Config::MissingEntry',
128
        'Exception thrown when missing csp_header_value';
129
130
    t::lib::Mocks::mock_config( $conf_csp_section, { opac => {} } );
131
    throws_ok { $csp->header_value } 'Koha::Exceptions::Config::MissingEntry',
132
        'Exception thrown when missing csp_header_value';
133
134
    t::lib::Mocks::mock_config( $conf_csp_section, { opac => { csp_header_value => '' } } );
135
    is( $csp->header_value, '', 'Even an empty csp_header_value is retrieved form koha-conf.xml' );
136
    t::lib::Mocks::mock_config( $conf_csp_section, { opac => { csp_header_value => 'some value' } } );
127
    t::lib::Mocks::mock_config( $conf_csp_section, { opac => { csp_header_value => 'some value' } } );
137
    is( $csp->header_value, 'some value', 'csp_header_value is retrieved from koha-conf.xml' );
128
    is( $csp->header_value, 'some value', 'csp_header_value is retrieved from koha-conf.xml' );
138
129
139
- 

Return to bug 38365