Skip to content

CSP Concepts

Content Security Policy (CSP) is a security standard that helps prevent cross-site scripting (XSS), clickjacking, and other code injection attacks.

CSP works by specifying which resources browsers are allowed to load for a given page. You define a policy using HTTP headers, and browsers enforce it.

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com

This policy says:

  • Load most resources only from the same origin ('self')
  • Load scripts from the same origin OR https://cdn.example.com

If a page tries to load a script from https://evil.com, the browser blocks it.

CSP has two modes:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri https://ingest.headerhawk.com/csp/YOUR_INGEST_CODE
  • Violations are reported but not blocked
  • Your site continues working normally
  • Use this to discover what your policy would break
Content-Security-Policy: default-src 'self'; report-uri https://ingest.headerhawk.com/csp/YOUR_INGEST_CODE
  • Violations are blocked and reported
  • Resources that violate the policy won’t load
  • Use this after tuning your policy in report-only mode
Directive Controls Example
default-src Fallback for other fetch directives default-src 'self'
script-src JavaScript sources script-src 'self' https://cdn.com
style-src CSS sources style-src 'self' 'unsafe-inline'
img-src Image sources img-src 'self' data: https:
font-src Font sources font-src 'self' https://fonts.com
connect-src URLs for fetch, XHR, WebSocket connect-src 'self' https://api.com
frame-src Sources for <iframe> frame-src 'none'
object-src Sources for <object>, <embed> object-src 'none'
base-uri URLs for <base> element base-uri 'self'
form-action URLs for form submissions form-action 'self'
frame-ancestors Who can embed this page in a frame frame-ancestors 'none'

The last three do not fall back to default-src. A policy of default-src 'none' still leaves your page embeddable and your forms free to post anywhere unless you write them out. Every directive has its own page in the directive reference.

Value Meaning
'self' Same origin as the document
'none' No sources allowed
'unsafe-inline' Allow inline scripts/styles (reduces security)
'unsafe-eval' Allow eval() and similar (reduces security)
https: Any HTTPS URL
data: Data URIs (e.g., data:image/png;base64,...)
blob: Blob URIs
https://example.com Specific origin

These are shared across directives, and there are more of them - 'unsafe-hashes', 'strict-dynamic', 'report-sample', scheme and wildcard host patterns. They all live on one page: CSP Keywords & Source Expressions.

For inline scripts without 'unsafe-inline', use nonces or hashes:

Content-Security-Policy: script-src 'nonce-abc123'
<script nonce="abc123">
// This script is allowed
</script>

Generate a new random nonce for each page load.

Content-Security-Policy: script-src 'sha256-abc123...'

The browser computes the hash of inline scripts and compares it to allowed hashes.

The report-uri directive tells browsers where to send violation reports:

Content-Security-Policy: default-src 'self'; report-uri https://ingest.headerhawk.com/csp/YOUR_INGEST_CODE

When a violation occurs, the browser sends a JSON report like:

{
"csp-report": {
"document-uri": "https://example.com/page",
"violated-directive": "script-src 'self'",
"blocked-uri": "https://evil.com/script.js",
"disposition": "enforce"
}
}

HeaderHawk collects and analyzes these reports for you.