Skip to content

Content Security Policy: Your Website's Unsung Hero

Published: at 09:47 AM

Content Security Policy (CSP) is an HTTP response header that provides an extra layer of security against common web attacks like Cross-Site Scripting (XSS), clickjacking, and other code injection vulnerabilities. Think of it as a firewall for your browser, dictating exactly what resources are allowed to load and execute.

Why You Absolutely Need CSP

XSS attacks remain a persistent threat. CSP drastically reduces the attack surface by allowing you to define trusted sources for scripts, styles, images, and other resources. By explicitly whitelisting sources, you prevent the browser from loading anything that doesn’t match your policy, effectively neutralizing many XSS attempts.

Core CSP Directives: The Must-Know Arsenal

Here’s a breakdown of the most essential CSP directives, complete with examples and explanations:

  1. default-src: The Fallback Directive

    • Purpose: Specifies the default source for all content types when a more specific directive isn’t defined. This is your baseline.

    • Usage:

      Content-Security-Policy: default-src 'self';
      
      • 'self': Allows resources from the same origin (scheme + host + port). Crucially important for basic protection.
    • Why it matters: Without default-src, the browser’s behavior is unpredictable. Always define it.

  2. script-src: Controlling JavaScript Execution

    • Purpose: Defines valid sources for JavaScript code. This is where you’ll spend most of your time.

    • Usage:

      Content-Security-Policy: script-src 'self' https://cdn.example.com;
      
      • 'self': Allows scripts from your domain.
      • https://cdn.example.com: Explicitly whitelists scripts from a specific CDN. Always use HTTPS.
    • Advanced Options (Use with Caution):

      • 'unsafe-inline': Allows inline JavaScript (e.g., <script>...</script>). Generally discouraged due to XSS risks. Only use if absolutely necessary and understand the implications.

      • 'unsafe-eval': Allows the use of eval() and related functions. Highly discouraged. Opens a massive security hole. Avoid at all costs.

      • 'nonce-{random-value}': Allows specific inline scripts that have a matching nonce attribute. Much safer than 'unsafe-inline'.

        <script nonce="your-random-value">
          // Your inline script
        </script>
        
        Content-Security-Policy: script-src 'nonce-your-random-value';
        
        • The nonce value must be cryptographically random and unique for each request. Generate it server-side.
      • 'strict-dynamic': Allows scripts loaded by trusted scripts to also load scripts. Useful for modern JavaScript frameworks that dynamically load modules. Requires 'self' or a nonce-based 'unsafe-inline'.

        Content-Security-Policy: script-src 'self' 'strict-dynamic';
        
    • Why it matters: Prevents the browser from executing malicious scripts injected into your page.

  3. style-src: Governing CSS Stylesheets

    • Purpose: Specifies valid sources for stylesheets.

    • Usage:

      Content-Security-Policy: style-src 'self' https://fonts.googleapis.com;
      
      • 'self': Allows stylesheets from your domain.
      • https://fonts.googleapis.com: Whitelists Google Fonts.
    • Advanced Options (Use with Caution):

      • 'unsafe-inline': Allows inline styles (e.g., <style>...</style> and style attributes). Discouraged for the same reasons as with scripts.
      • 'unsafe-hashes': Allows specific inline styles based on their SHA256, SHA384, or SHA512 hash. More secure than 'unsafe-inline' but still complex to manage.
    • Why it matters: Prevents attackers from injecting malicious CSS that could alter your site’s appearance or steal user data.

  4. img-src: Controlling Images

    • Purpose: Defines valid sources for images.

    • Usage:

      Content-Security-Policy: img-src 'self' data: https://images.example.com;
      
      • 'self': Allows images from your domain.
      • data:: Allows images embedded as data URIs (Base64 encoded). Use sparingly.
      • https://images.example.com: Whitelists images from a specific image server.
    • Why it matters: Prevents attackers from displaying malicious images or tracking users through image requests.

  5. font-src: Specifying Font Sources

    • Purpose: Defines valid sources for fonts.

    • Usage:

      Content-Security-Policy: font-src 'self' https://fonts.gstatic.com;
      
      • 'self': Allows fonts from your domain.
      • https://fonts.gstatic.com: Whitelists Google Fonts.
    • Why it matters: Prevents attackers from injecting malicious fonts that could exploit browser vulnerabilities.

  6. connect-src: Governing AJAX and WebSockets

    • Purpose: Defines valid sources for XMLHttpRequest, Fetch API, WebSockets, and EventSource connections. Critical for modern web applications.

    • Usage:

      Content-Security-Policy: connect-src 'self' https://api.example.com wss://ws.example.com;
      
      • 'self': Allows connections to your domain.
      • https://api.example.com: Whitelists connections to a specific API endpoint.
      • wss://ws.example.com: Whitelists WebSocket connections. Always use wss:// for secure WebSockets.
    • Why it matters: Prevents attackers from making unauthorized requests to external APIs or intercepting sensitive data transmitted over WebSockets.

  7. frame-src and child-src (Deprecated, but Important History)

    • Purpose: Defined valid sources for nested browsing contexts (iframes).

    • frame-src: Deprecated in favor of child-src.

    • child-src: Replaced by frame-src, worker-src, and connect-src.

    • Usage (for Legacy Browsers):

      Content-Security-Policy: frame-src 'self' https://youtube.com;
      
    • Modern Usage: Use frame-src for iframes, worker-src for web workers, and connect-src for AJAX/WebSockets.

    • Why it matters: Prevents clickjacking attacks and restricts the content that can be embedded in your site.

  8. worker-src: Controlling Web Workers

    • Purpose: Defines valid sources for web worker scripts.

    • Usage:

      Content-Security-Policy: worker-src 'self' blob:;
      
      • 'self': Allows web workers from your domain.
      • blob:: Allows web workers created from Blob URLs.
    • Why it matters: Prevents attackers from running malicious code in background threads.

  9. object-src: Governing Plugins (Deprecated, but Important)**

    • Purpose: Defines valid sources for plugins like Flash and Java applets. Largely irrelevant today as these technologies are obsolete.

    • Usage:

      Content-Security-Policy: object-src 'none';
      
      • 'none': Recommended. Disables all plugins.
    • Why it matters: Plugins are a major security risk. Disable them unless you have a very specific reason to use them.

  10. base-uri: Restricting <base> Tag

    • Purpose: Defines valid URLs that can be used in a <base> element.

    • Usage:

      Content-Security-Policy: base-uri 'self';
      
      • 'self': Allows <base> tags that point to your domain.
    • Why it matters: Prevents attackers from redirecting relative URLs to malicious sites.

  11. form-action: Controlling Form Submissions

    • Purpose: Defines valid URLs that can be used as the action attribute of a <form> element.

    • Usage:

      Content-Security-Policy: form-action 'self' https://secure.example.com;
      
      • 'self': Allows form submissions to your domain.
      • https://secure.example.com: Whitelists form submissions to a specific secure endpoint.
    • Why it matters: Prevents attackers from redirecting form submissions to malicious sites to steal user data.

  12. upgrade-insecure-requests: Enforcing HTTPS

    • Purpose: Instructs the browser to automatically upgrade all insecure HTTP URLs to HTTPS.

    • Usage:

      Content-Security-Policy: upgrade-insecure-requests;
      
    • Why it matters: Ensures that all communication with your site is encrypted, protecting user data from eavesdropping. Essential for HTTPS-only sites.

  13. block-all-mixed-content: Blocking Mixed Content

    • Purpose: Prevents the browser from loading any HTTP resources on an HTTPS page.

    • Usage:

      Content-Security-Policy: block-all-mixed-content;
      
    • Why it matters: Prevents man-in-the-middle attacks that could compromise the security of your HTTPS site.

  14. report-uri (Deprecated)

    • Purpose: Specifies a URL where the browser should send CSP violation reports.

    • Usage (Deprecated):

      Content-Security-Policy: report-uri /csp-report-endpoint;
      
    • Why it’s deprecated: Replaced by report-to.

  15. report-to: Modern Reporting Mechanism

    • Purpose: Specifies a named endpoint (defined in a Report-To header) where the browser should send CSP violation reports. The modern way to handle CSP reporting.

    • Usage:

      Report-To: {
        "group": "csp-endpoint",
        "max_age": 31536000,
        "endpoints": [{"url": "https://example.com/csp-report-endpoint"}]
      }
      Content-Security-Policy: report-to csp-endpoint;
      
      • Report-To: Defines the reporting endpoint.
        • group: A name for the endpoint.
        • max_age: How long the browser should cache the endpoint configuration (in seconds).
        • endpoints: An array of URLs where reports should be sent.
      • Content-Security-Policy: report-to csp-endpoint;: Tells the browser to use the csp-endpoint defined in the Report-To header.
    • Why it matters: Allows you to monitor CSP violations and identify potential security issues.

CSP in Report-Only Mode

Best Practices: The Path to CSP Mastery

  1. Start with default-src 'self': This is your foundation.
  2. Use Report-Only Mode: Test your CSP thoroughly before enforcing it.
  3. Monitor CSP Reports: Use report-to to identify violations and refine your policy.
  4. Avoid 'unsafe-inline' and 'unsafe-eval': These are security risks. Use nonces or hashes instead.
  5. Be Specific: Whitelist only the resources you need. Avoid wildcarding.
  6. Use HTTPS: Always use HTTPS for all resources.
  7. Automate CSP Generation: Use a tool or library to generate your CSP dynamically.
  8. Regularly Review and Update: CSP is not a set-it-and-forget-it solution. Review and update your policy as your application evolves.

Example CSP Header: A Solid Starting Point

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.jsdelivr.net 'nonce-{random-nonce}' 'strict-dynamic';
  style-src 'self' https://fonts.googleapis.com 'unsafe-inline';
  img-src 'self' data: https://images.example.com;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com wss://ws.example.com;
  frame-src 'self' https://youtube.com;
  object-src 'none';
  base-uri 'self';
  form-action 'self' https://secure.example.com;
  upgrade-insecure-requests;
  block-all-mixed-content;
  report-to csp-endpoint;

Remember to replace {random-nonce} with a cryptographically random value generated server-side for each request.

Conclusion: Embrace CSP, Secure Your Site

CSP is a powerful tool that can significantly improve the security of your website. By understanding the core directives and following best practices, you can create a robust CSP that protects your users from a wide range of attacks. Embrace CSP, and make your website a safer place.


Next Post
Real‑Time Coinbase OHLCV Streaming with Node.js Native WebSocket & TypeScript