FrontendPrep
Menu
Topics
Questions
Guides
Challenges
Soon
Back to Web Security Questions
securityHard

Web Security: Content Security Policy (CSP) in Depth

Master Content Security Policy (CSP). Learn how to declare strict CSP directives, use nonces and hashes, restrict object/script sources, and set up violation report logging.

Web Security: Content Security Policy (CSP) in Depth

One of the most frequent advanced security questions in frontend interviews is:

What is Content Security Policy (CSP)? How do you build a strict CSP directive, and how do nonces and hashes protect against Cross-Site Scripting (XSS)?

Content Security Policy (CSP) is an HTTP response header that defines which resources (scripts, stylesheets, images, connections) the browser is allowed to load and execute for a specific webpage. It acts as a powerful layer of defense to mitigate Cross-Site Scripting (XSS) and data injection attacks.


1. Declarative CSP Directives

The Content-Security-Policy header contains a semi-colon separated list of directives:

Content-Security-Policy: default-src 'self'; script-src 'self' https://trustedscripts.com; img-src 'self' data:;

Core Directives:

  • default-src: Fallback policy for other resource fetch directives when they are not explicitly specified.
  • script-src: Restricts the origins that can execute JavaScript on the page.
  • style-src: Restricts CSS source origins.
  • img-src: Restricts image source origins.
  • connect-src: Restricts the target URLs that client-side JavaScript can request (using fetch, XMLHttpRequest, or WebSockets).
  • frame-ancestors: Restricts which sites can embed this page inside an <iframe>, preventing Clickjacking attacks.

2. Eliminating 'unsafe-inline' with Nonces and Hashes

By default, strict CSP configurations block inline scripts:

<script>runMaliciousCode();</script> <!-- Blocked by strict CSP! -->

Historically, developers resolved this by adding 'unsafe-inline' to the script-src directive, which completely defeats the anti-XSS benefits of CSP. Instead, you should use:

A. Nonces (Number used once)

A nonce is a cryptographically strong, randomly generated token generated by the server on every single page request:

  1. The server generates a unique token (e.g. d392a83f982) and adds it to the HTTP CSP header:
    Content-Security-Policy: script-src 'self' 'nonce-d392a83f982';
  2. The server injects the matching attribute to valid inline script tags in the HTML document:
    <script nonce="d392a83f982">console.log("Safe script run!");</script>

If an attacker injects a script tag without the correct matching nonce token, the browser blocks execution.

B. Hashes

If you have static inline scripts that do not change, you can compute their SHA-256 hash and declare the hash signature inside the CSP header:

  1. Compute the hash of the exact script content: console.log("Hello"); -> sha256-R43...
  2. Define the hash in the CSP header:
    Content-Security-Policy: script-src 'self' 'sha256-R43uF5...';

3. CSP Violation Reporting

You can monitor policy violations in production without blocking resources by using the Content-Security-Policy-Report-Only header combined with a report URI destination:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri https://api.my-app.com/csp-report;

The browser will send a JSON payload to the report-uri whenever a policy restriction is violated, helping you identify and fix bugs before enforcing strict blocking.


Key Takeaways

  • Strict Fallbacks: Always set a restrictive default-src 'self' fallback policy.
  • Avoid Unsafe Keywords: Never use 'unsafe-inline' or 'unsafe-eval' in production stylesheets or scripts unless absolutely necessary.
  • Dynamic Nonces: Generate unique nonces per request on server rendering passes; do not use static reusable nonces.
  • Report-Only for Staging: Use the Report-Only header to validate CSP configs before fully rolling out blocking headers.

Share this Resource

Help other developers level up by sharing this study guide.

More Technical Questions

Expand your mastery. Deep dive into other frontend interview challenges in this category.