Docs / Security / How to Implement Content Security Policy (CSP) Headers in Depth

How to Implement Content Security Policy (CSP) Headers in Depth

By Admin · Mar 15, 2026 · Updated Apr 23, 2026 · 307 views · 2 min read

Content Security Policy is an HTTP header that tells browsers which sources of content are trusted. A well-configured CSP prevents Cross-Site Scripting (XSS), clickjacking, and other code injection attacks by restricting where scripts, styles, and other resources can be loaded from.

How CSP Works

# The browser enforces CSP rules:
# 1. Server sends Content-Security-Policy header
# 2. Browser parses the policy directives
# 3. Any resource load that violates the policy is blocked
# 4. Violations are reported (if report-uri is configured)

Building a CSP Policy

# Start restrictive and loosen as needed
# Nginx example:
add_header Content-Security-Policy "
  default-src 'self';
  script-src 'self' https://cdn.jsdelivr.net;
  style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
  font-src 'self' https://fonts.gstatic.com;
  img-src 'self' data: https:;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
" always;

CSP Directives Reference

  • default-src — Fallback for all resource types
  • script-src — JavaScript sources
  • style-src — CSS sources
  • img-src — Image sources
  • font-src — Font sources
  • connect-src — AJAX, WebSocket, fetch destinations
  • media-src — Audio and video sources
  • frame-src — iframe sources
  • frame-ancestors — Who can iframe your page (replaces X-Frame-Options)
  • base-uri — Restricts the base element
  • form-action — Where forms can submit to

Testing with Report-Only Mode

# Use Content-Security-Policy-Report-Only to test without blocking
add_header Content-Security-Policy-Report-Only "
  default-src 'self';
  script-src 'self';
  report-uri /csp-report;
" always;

# This logs violations without breaking your site
# Review reports and adjust the policy before enforcing

Common CSP Patterns

# Strict CSP for a static site
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'

# CSP for a site using Google Analytics and Fonts
Content-Security-Policy: default-src 'self'; script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' https://www.google-analytics.com; connect-src 'self' https://www.google-analytics.com

# CSP with nonce-based script execution (strongest)
# Generate a unique nonce per request
Content-Security-Policy: script-src 'nonce-abc123'; style-src 'nonce-abc123'
# Then in HTML: <script nonce="abc123">...</script>

Other Security Headers

# Complete security headers in Nginx:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "0" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

Testing Your Headers

# Check headers with curl
curl -I https://yourdomain.com

# Online tools:
# https://securityheaders.com
# https://observatory.mozilla.org
# Aim for an A+ rating on both

Was this article helpful?