Collecting Content Security Policy (CSP) Reports

2023-02-03 - 6 min read

In this post, we'll be showcasing the internal logging facility. Our use case involves collecting and aggregating Content Security Policy (CSP) reports. We will convert the stream of reports into meaningful data. The described application is available as a template. You can install it from the "Templates" section in your Flowlet workspace.

What is the CSP header?

Content Security Policy (CSP) is a security mechanism. It helps to prevent cross-site scripting (XSS) and other code injection attacks. With CSP, a website declares which content sources are trusted and which are not.

When a browser loads a page with a CSP header, it enforces the policy by blocking any content that doesn't match the declared sources. In case of any security violation, the browser can send a report to the specified report-uri endpoint. This report contains information about the blocked content. Developers use that data to identify and fix the issue.

Here is an example of what a CSP header might look like:

Content-Security-Policy: default-src 'self';
  script-src 'self' https://ajax.googleapis.com;
  object-src 'none';
  report-uri https://[WORKSPACE].flowlet.app/api/csp-report

In this example, the policy allows content from the current origin ('self') and scripts from the current origin and https://ajax.googleapis.com. The policy also disallows objects from any origin ('none'). Furthermore, it specifies the report-uri endpoint where the browser can send CSP reports.

The new Report-To header

The report-uri directive in the Content Security Policy (CSP) header is now deprecated and replaced by the report-to rule and a new Report-To header. You should include both for compatibility.

The new Report-To header is used in conjunction with the report-to directive. It provides a JSON object that defines a named reporting group consisting of multiple endpoints where reports can be sent. Below is an example of a CSP header and Report-To header that uses both report-uri and report-to for compatibility:

Content-Security-Policy: default-src 'self'; report-uri https://[WORKSPACE].flowlet.app/api/csp-report; report-to csp-endpoint
Report-To: {"group":"csp-endpoint", "max_age":10886400, "endpoints":[{"url":"https://[WORKSPACE].flowlet.app/api/csp-report"}]}

In this example, the CSP header specifies a default source of 'self' and includes both report-uri and report-to directives. The report-uri rule sends CSP reports to the specified URI. The report-to directive associates the reporting group with the named reporting group defined in the Report-To header.

What is the report request?

The browser sends a CSP report request to the report-uri endpoint specified in the CSP header. The request is an HTTP POST request with a JSON payload that contains information about the violation.

Here is an example of what a CSP report request might look like:

POST /api/csp-report
Content-Type: application/csp-report

{
  "csp-report": {
    "document-uri": "https://example.com/page.html",
    "referrer": "",
    "violated-directive": "script-src 'self' https://ajax.googleapis.com",
    "effective-directive": "script-src",
    "original-policy": "default-src 'self'; script-src 'self' https://ajax.googleapis.com; object-src 'none'; report-uri https://[WORKSPACE].flowlet.app/api/csp-report",
    "disposition": "enforce",
    "blocked-uri": "https://example.com/evil-script.js",
    "status-code": 200,
    "script-sample": ""
  }
}

In this example, the report contains information about violating the script-src directive. The document-uri, violated-directive, and blocked-uri fields provide information about the page and the source of the blocked content.

The CSP report request provides valuable information for developers to identify and fix security issues. With Flowlet, this information can be easily written to the log and aggregated for further analysis.

Catching the reports in Flowlet

Flowlet makes it easy to catch and process CSP reports. The first step is an HTTP endpoint flow that listens for incoming CSP reports. It's configured to listen on the URL /api/csp-report and to receive POST requests.

HTTP endpoint configuration

The screenshot above shows the configuration that we use. We do not use the logging option here because it logs much more data than needed. Make sure to allow CORS requests because the website runs on a different domain.

We'll only use the document-uri, violated-directive, and blocked-uri. The report may (and will) include more data, but we can ignore that for our use case.

The incoming data is validated automatically. We only have to write the required data to the log, which we can do using the "Log" block.

Flow for writing CSP reports to the log

Test the flow by sending a CSP report to the endpoint using the curl command below.

curl -H 'Content-Type: application/csp-report' \
-d '{
  "csp-report": {
    "document-uri": "https://example.com/foo/bar",
    "violated-directive": "default-src self",
    "blocked-uri": "http://evilhackerscripts.com"
  }
}' https://[WORKSPACE].flowlet.app/api/csp-report

Now you should see the logged message in the flowlet admin:

The CSP report in the Flowlet logs

Processing the reports in an automated task

Once the HTTP endpoint flow is set up, the next step is to aggregate the data from the log. The goal is to keep a list of actual CSP violations in a database table called CspPage.

Definition for the CspPage table

Flowlet provides automated tasks that can run periodically and read the log messages from the last hour. The task can then aggregate the data and write it to the database for further inspection.

This flow is quite extensive and contains two loops. The steps are:

  1. Read all log messages from the last hour from the log named "csp".
  2. For each message, check if a record with an identical violation and blocked resource already exists.
  3. Update that record if it does, and it has an earlier date. Otherwise, we will write a new table row.
  4. Read all database records with a date prior to 24 hours ago.
  5. Loop through these records to delete them.

The flow is executed hourly and keeps the database table up-to-date.

The automated task flow to process log messages

After running the example command and the automated task, you'll see a new record in the database.

Data in the CspPage table

You may want to run the automated task manually with the "Test flow" button.

Extending the process

Once you have set up the HTTP endpoint flow and automated task, there are many ways to extend the solution to take further action. Here are a few examples:

  • Flowlet can send notifications to your security team when the automated task runs found CSP reports.
  • Generate reports based on the aggregated data. For example, you can create a daily statement that shows the number of reports by violation type or a weekly report that shows the top 10 blocked URIs.
  • Monitor trends: By aggregating CSP reports over time, you can identify trends.

These are just a few examples of what you can make with Flowlet to catch and process CSP reports. The platform provides a flexible and scalable solution for API integration. Also, it makes it easy to extend the solution to meet your specific needs.

Starting with this template, you can easily catch and process CSP reports in Flowlet.