Content Security Policy

Overview

The Datadog Content Security Policy (CSP) integration sends logs to Datadog from web browsers as they interpret your CSP and detect violations. By using the CSP integration, you don’t have to host or manage a dedicated endpoint to aggregate your CSP data.

For more information about CSP, see Content-Security-Policy.

Prerequisites

Before you add a directive to a CSP header, generate a client token in your Datadog account.

For security reasons, you must use a client token to collect logs from web browsers. You cannot use Datadog API keys to configure the Datadog Browser Logs SDK as they would be exposed client-side. For more information, see the client token documentation for more details.

Prepare a URL for the CSP

You need a URL where browsers can send policy violation reports. The URL must have the following format:

https:///api/v2/logs?dd-api-key=<client-token>&dd-evp-origin=content-security-policy&ddsource=csp-report

Optionally, add the ddtags key (service name, the environment, and service version) to the URL to set up Unified Service Tagging:

  • env: the application’s environment.
  • service: the service name for your application.
  • version: the application’s version.

When formatting the ddtags values, you must:

  • Group keys and values with a colon (:)
  • Concatenate keys and values with a comma (,)
  • Use URL encoding

For example, given the key-value pairs {"service": "billingService", "env": "production"}, the URL-encoded string would look like this:

service%3AbillingService%2Cenv%3Aproduction

And the final URL with tags would be:

https:///api/v2/logs?dd-api-key=<client-token>&dd-evp-origin=content-security-policy&ddsource=csp-report&ddtags=service%3AbillingService%2Cenv%3Aproduction

Add the URL to the CSP

You can either embed the URL in an HTTP header (recommended), or embed it in a <meta> HTML tag.

Embed the policy in an HTTP header

Datadog recommends embedding the Content Security Policy in an HTTP header. You can either use the report-uri directive or the report-to directive. The report-to directive will eventually supersede report-uri, but is not yet supported by all browsers.

  • If you’re using the report-uri directive:

    Content-Security-Policy: ...; report-uri https:///api/v2/logs?dd-api-key=<client-token>&dd-evp-origin=content-security-policy&ddsource=csp-report
    
  • If you’re using the report-to directive:

    Content-Security-Policy: ...; report-to browser-intake-datadoghq
    Report-To: { "group": "browser-intake-datadoghq",
                "max_age": 10886400,
                "endpoints": [
                    { "url": "https:///api/v2/logs?dd-api-key=<client-token>&dd-evp-origin=content-security-policy&ddsource=csp-report" }
                ] }
    

Policy embedded in a <meta> HTML tag

You can also embed the URL in a <meta> HTML tag.

<meta http-equiv="Content-Security-Policy"
    content="...; report-uri 'https:///api/v2/logs?dd-api-key=<client-token>&dd-evp-origin=content-security-policy&ddsource=csp-report'">

Violation reports examples

Each browser interprets the report format differently:

{
  'csp-report': {
    'blocked-uri': 'https://evil.com/malicious.js',
    'document-uri': 'http://localhost:8000/',
    'original-policy': 'script-src http://good.com; report-uri http://127.0.0.1:8000/csp_reports',
    referrer: '',
    'violated-directive': 'script-src'
  }
}
{
  'csp-report': {
    'document-uri': 'http://localhost:8000/',
    referrer: '',
    'violated-directive': 'script-src-elem',
    'effective-directive': 'script-src-elem',
    'original-policy': 'trusted-types toto; script-src good.com; report-uri http://127.0.0.1:8000/csp_reports',
    disposition: 'enforce',
    'blocked-uri': 'https://evil.com/malicious.js',
    'status-code': 200,
    'script-sample': ''
  }
}
{
  'csp-report': {
    'document-uri': 'http://localhost:8000/',
    referrer: '',
    'violated-directive': 'script-src good.com',
    'effective-directive': 'script-src',
    'original-policy': 'trusted-types toto; script-src good.com; report-uri http://127.0.0.1:8000/csp_reports',
    'blocked-uri': 'https://evil.com',
    'status-code': 200
  }
}

Use CSP with Real User Monitoring and Session Replay

If you’re using CSP on your websites, add the following URLs to your existing directives depending on your use case.

Intake URLs

Depending on the site option used to initialize Real User Monitoring or browser log collection, add the appropriate connect-src entry:

connect-src https://

Web Worker

If you are using Session Replay or the RUM compressIntakeRequests initialization parameter, make sure to allow workers with blob: URI schemes by adding the following worker-src entry:

worker-src blob:;

Alternatively, starting from version 4.47.0, you can self-host the Datadog Browser SDK Worker JavaScript file and provide the workerUrl option to initialize the RUM Browser SDK by doing one of the following:

Requirements:

  • Make sure the Worker major version matches the Browser SDK version you are using.
  • Host the file on the same origin as your web application. Due to browser restrictions, it cannot be hosted on a separate domain (for example, a third-party CDN host) or a different scheme.

CDN bundle URL

If you are using the CDN async or CDN sync setup for Real User Monitoring or browser log collection, also add the following script-src entry:

script-src https://www.datadoghq-browser-agent.com

Further Reading

Additional helpful documentation, links, and articles: