Enhance Web Security with Content Security Policy
Learn how to implement a Content Security Policy (CSP) to protect your web applications from common attacks like XSS and data injection.
Web applications are constantly targeted by various security threats, most notably Cross-Site Scripting (XSS) and data injection attacks. These vulnerabilities can allow attackers to inject malicious code into your website, compromising user data, session tokens, and overall application integrity. Traditional server-side defenses, while crucial, often fall short in preventing client-side attacks once a vulnerability has been exploited. This is where Content Security Policy (CSP) provides a powerful, client-side layer of defense.
What is Content Security Policy (CSP)?
Content Security Policy (CSP) is a web security standard that helps prevent various types of code injection attacks, including XSS. It does this by specifying trusted content sources that the browser is allowed to load and execute for a given page. Essentially, you provide a whitelist of domains and behaviors, and the browser will block anything that violates these rules. This dramatically reduces the attack surface for malicious content.
CSP works as a declaration that tells the browser, "Only load scripts from these domains, only apply styles from these sources, and so on." If the browser attempts to load content from a source not explicitly allowed by the CSP, it will block the request and optionally report the violation. This control applies to scripts, stylesheets, images, media, fonts, frames, web workers, and more.
How CSP Works
CSP is primarily enforced by the browser based on an HTTP response header or a HTML meta tag. The most common and recommended approach is to include a Content-Security-Policy HTTP header in your server's responses. When a browser receives this header, it parses the policy directives and enforces them for all resources requested by that page. If a resource request violates the policy, the browser typically blocks it and may send a violation report to a specified URI.
Each policy consists of one or more directives, each governing a specific type of resource or behavior. For example, the script-src directive controls JavaScript sources, style-src controls CSS sources, and img-src controls image sources. The default-src directive acts as a fallback for any resource type not explicitly covered by another directive.
Implementing a Basic CSP
To implement a CSP, you typically configure your web server or application framework to send the Content-Security-Policy HTTP header. Let's start with a restrictive baseline and then add exceptions.
-
Start with a strict
default-src: This directive specifies the default policy for fetching resources. Setting it to'self'is a strong starting point, meaning only resources from the current origin are allowed.Content-Security-Policy: default-src 'self'; -
Add specific directives for common resources: You will likely need to allow resources from other trusted domains, such as CDNs, analytics scripts, or embedded content. Here's an example allowing Google Analytics and a custom CDN:
Content-Security-Policy: default-src 'self'; script-src 'self' https://www.google-analytics.com https://cdn.example.com; style-src 'self' https://cdn.example.com; img-src 'self' data: https://cdn.example.com;script-src: Allows JavaScript from your origin, Google Analytics, andcdn.example.com.style-src: Allows stylesheets from your origin andcdn.example.com.img-src: Allows images from your origin,data:URIs (for inline images), andcdn.example.com.
-
Consider reporting violations: Use the
report-uriorreport-todirective to send violation reports to a specified endpoint. This helps you identify and fix CSP issues without immediately blocking content.Content-Security-Policy: default-src 'self'; script-src 'self' https://www.google-analytics.com; report-uri /csp-violation-report-endpoint;Initially, you might want to use
Content-Security-Policy-Report-Onlyheader instead ofContent-Security-Policy. This allows you to test your policy and collect reports without actually enforcing blocks, preventing potential breakage of your site.Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://www.google-analytics.com; report-uri /csp-violation-report-endpoint;
Refining Your CSP
Creating an effective CSP often requires careful refinement. Here are key considerations:
-
Inline Scripts and Styles: Directives like
script-srcandstyle-srcinherently block inline JavaScript (<script>...</script>) and inline CSS (<style>...</style>,style="..."). To allow specific inline content, you must use cryptographically secure nonces or hashes.-
Nonces: A unique, unguessable value generated on each page load. You add the nonce to both the CSP header and the inline script/style tag.
Content-Security-Policy: script-src 'nonce-RANDOM_VALUE';<script nonce="RANDOM_VALUE"> /* your inline script */ </script> -
Hashes: A SHA256, SHA384, or SHA512 hash of the inline script/style content. The browser calculates the hash and compares it to the policy.
Content-Security-Policy: script-src 'sha256-BASE64_ENCODED_HASH';<script> console.log('Hello, world.'); </script>The hash for
console.log('Hello, world.');issha256-DQyJp5yH7sUfXq8t/Iq6Pj0eJ7bL/Qx/Yj+y/1+N/5M=
-
-
'unsafe-inline'and'unsafe-eval': Avoid these directives if possible.'unsafe-inline'allows all inline scripts/styles, negating much of CSP's XSS protection.'unsafe-eval'allows JavaScripteval()and similar functions, which can also be exploited. Use nonces or hashes for specific inline content. If you absolutely must use them, be aware of the security implications. -
Frame Control: Use
frame-srcfor<iframe>,<frame>,<object>,<embed>, and<applet>. Useframe-ancestorsto control which sources can embed your page (e.g., in an<iframe>).Content-Security-Policy: frame-src 'self' https://trusted-embed.com; frame-ancestors 'self' https://your-parent-domain.com; -
Workers: For Web Workers or Service Workers, use
worker-src.
Common Pitfalls and Best Practices
Implementing CSP can be tricky, especially on existing large applications. Here are some tips:
- Incremental Rollout: Start with a
Content-Security-Policy-Report-Onlyheader. Monitor violation reports for a period. This allows you to identify all necessary directives before enforcing the policy, preventing site breakage. - Be Specific: Always try to specify exact domains rather than broad wildcards (e.g.,
*.example.com). - Review Third-Party Scripts: Understand what every third-party script on your site does and where it fetches resources from. They often require additional CSP directives.
- Avoid Hash Collisions: When using hashes for inline scripts, ensure the exact script content matches the hash. Even a single character change invalidates the hash.
- Performance: While CSP itself has minimal performance impact, an overly complex policy might slightly increase parsing time. Keep it as streamlined as possible.
- Browser Support: CSP Level 2 and Level 3 offer more features and wider browser support. Most modern browsers support core CSP directives. Always provide a robust fallback or progressive enhancement for users on older browsers.
Takeaway and Checklist
Content Security Policy is a critical security layer for modern web applications, effectively mitigating XSS and other injection attacks by whitelisting trusted content sources. Proper implementation requires careful planning and testing, but the security benefits are substantial.
CSP Implementation Checklist:
- Start with
Content-Security-Policy-Report-Onlyto monitor violations. - Set a strict
default-src 'self'directive. - Identify and whitelist all necessary script, style, image, and other resource sources.
- Replace
'unsafe-inline'and'unsafe-eval'with nonces or hashes where absolutely necessary. - Configure
report-uriorreport-tofor violation reporting. - Test your policy thoroughly across different browsers and user flows.
- Switch to
Content-Security-Policyonce you are confident the policy does not break your site.