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

(-)a/Koha/REST/V1/CSPReports.pm (-33 / +43 lines)
Lines 46-88 is violated. This endpoint logs those reports for administrator review. Link Here
46
sub add {
46
sub add {
47
    my $c = shift->openapi->valid_input or return;
47
    my $c = shift->openapi->valid_input or return;
48
48
49
    my $report = $c->req->json;
50
51
    # CSP reports come wrapped in a 'csp-report' key
52
    my $csp_report = $report->{'csp-report'} // $report->{'body'} // $report;
53
54
    my $logger = Koha::Logger->get( { interface => 'csp' } );
49
    my $logger = Koha::Logger->get( { interface => 'csp' } );
55
50
56
    # Extract key fields for logging
51
    my @reports           = ();
57
    my $document_uri  = $csp_report->{'document-uri'}       // 'unknown';
52
    my $reports_from_json = $c->req->json;
58
    my $violated_dir  = $csp_report->{'violated-directive'} // 'unknown';
53
    if ( ref $reports_from_json eq 'ARRAY' ) {
59
    my $blocked_uri   = $csp_report->{'blocked-uri'}        // 'unknown';
60
    my $source_file   = $csp_report->{'source-file'}        // '';
61
    my $line_number   = $csp_report->{'line-number'}        // '';
62
    my $column_number = $csp_report->{'column-number'}      // '';
63
64
    # Build location string if available
65
    my $location = '';
66
    if ($source_file) {
67
        $location = " at $source_file";
68
        $location .= ":$line_number"   if $line_number;
69
        $location .= ":$column_number" if $column_number;
70
    }
71
54
72
    $logger->warn(
55
        #FIXME: We could just take the top X number of reports...
73
        sprintf(
56
        push( @reports, @$reports_from_json );
74
            "CSP violation: '%s' blocked '%s' on page '%s'%s",
57
    } elsif ( ref $reports_from_json eq 'HASH' ) {
75
            $violated_dir,
58
        push( @reports, $reports_from_json );
76
            $blocked_uri,
59
    }
77
            $document_uri,
78
            $location
79
        )
80
    );
81
60
82
    # Log full report at debug level for detailed analysis
61
    # CSP reports come wrapped in a 'csp-report' key
83
    if ( $logger->is_debug ) {
62
    foreach my $report (@reports) {
84
        require JSON;
63
        my $csp_report = $report->{'csp-report'} // $report->{body};
85
        $logger->debug( "CSP report details: " . JSON::encode_json($csp_report) );
64
65
        # Extract key fields for logging
66
        my $document_uri  = $csp_report->{'documentURL'}        // $csp_report->{'document-uri'}        // 'unknown';
67
        my $violated_dir  = $csp_report->{'effectiveDirective'} // $csp_report->{'effective-directive'} // 'unknown';
68
        my $blocked_uri   = $csp_report->{'blockedURL'}         // $csp_report->{'blocked-uri'}         // 'unknown';
69
        my $source_file   = $csp_report->{'sourceFile'}         // $csp_report->{'source-file'}         // '';
70
        my $line_number   = $csp_report->{'lineNumber'}         // $csp_report->{'line-number'}         // '';
71
        my $column_number = $csp_report->{'columnNumber'}       // $csp_report->{'column-number'}       // '';
72
73
        # Build location string if available
74
        my $location = '';
75
        if ($source_file) {
76
            $location = " at $source_file";
77
            $location .= ":$line_number"   if $line_number;
78
            $location .= ":$column_number" if $column_number;
79
        }
80
81
        $logger->warn(
82
            sprintf(
83
                "CSP violation: '%s' blocked '%s' on page '%s'%s",
84
                $violated_dir,
85
                $blocked_uri,
86
                $document_uri,
87
                $location
88
            )
89
        );
90
91
        # Log full report at debug level for detailed analysis
92
        if ( $logger->is_debug ) {
93
            require JSON;
94
            $logger->debug( "CSP report details: " . JSON::encode_json($csp_report) );
95
        }
86
    }
96
    }
87
97
88
    return $c->render(
98
    return $c->render(
(-)a/api/v1/swagger/definitions/csp_report_body.yaml (+56 lines)
Line 0 Link Here
1
---
2
type: object
3
description: |
4
  A Content-Security-Policy violation report as sent by browsers.
5
  See https://www.w3.org/TR/CSP3/#violation-reports for specification.
6
properties:
7
  documentURL:
8
    type: string
9
    description: The URI of the document where the violation occurred
10
    maxLength: 200
11
  referrer:
12
    type: string
13
    description: The referrer of the document where the violation occurred
14
    maxLength: 200
15
  effectiveDirective:
16
    type: string
17
    description: The effective directive that was violated
18
    maxLength: 100
19
  originalPolicy:
20
    type: string
21
    description: The original CSP policy as specified in the header
22
    maxLength: 400
23
  disposition:
24
    type: string
25
    description: Either "enforce" or "report" depending on CSP mode
26
    enum:
27
      - enforce
28
      - report
29
  blockedURL:
30
    type: string
31
    description: The URI of the resource that was blocked
32
    maxLength: 200
33
  lineNumber:
34
    type: integer
35
    description: Line number in the document where the violation occurred
36
    minimum: 0
37
    maximum: 999999
38
  columnNumber:
39
    type: integer
40
    description: Column number where the violation occurred
41
    maximum: 999999
42
    minimum: 0
43
  sample:
44
      type: string
45
      description: First 40 characters of the inline script that caused the violation
46
      maxLength: 41
47
  sourceFile:
48
    type: string
49
    description: The URI of the script where the violation occurred
50
    maxLength: 200
51
  statusCode:
52
    type: integer
53
    description: HTTP status code of the document
54
    minimum: 0
55
    maximum: 999
56
additionalProperties: true
(-)a/api/v1/swagger/definitions/csp_report_uri_to.yaml (-12 / +11 lines)
Lines 1-27 Link Here
1
---
1
---
2
type: object
2
type:
3
  - array
4
  - object
3
description: |
5
description: |
4
  A Content-Security-Policy violation report as sent by browsers.
6
  A Content-Security-Policy violation report as sent by browsers.
5
  See https://www.w3.org/TR/CSP3/#violation-reports for specification.
7
  See https://www.w3.org/TR/CSP3/#violation-reports for specification.
6
properties:
8
properties:
7
  csp-report:
9
  csp-report:
8
    $ref: "csp_report.yaml"
10
    $ref: "csp_report.yaml"
11
  age:
12
    type: integer
13
    minimum: 0
14
    maximum: 9999999999
9
  body:
15
  body:
10
    $ref: "csp_report.yaml"
16
    $ref: "csp_report_body.yaml"
11
  user_agent:
17
  user_agent:
12
    type: string
18
    type: string
13
    maxLength: 300
19
    maxLength: 300
14
  destination:
15
    type: string
16
    maxLength: 200
17
  url:
20
  url:
18
    type: string
21
    type: string
19
    maxLength: 200
22
    maxLength: 200
20
  timestamp:
23
  type:
21
    type: string
24
    type: string
22
    maxLength: 50
25
    enum:
23
  attempts:
26
      - "csp-violation"
24
    type: integer
25
    minimum: 0
26
    maximum: 99
27
additionalProperties: true
27
additionalProperties: true
28
- 

Return to bug 38365