HTTP Headers vs Meta Tags Implementation
Understanding CSP Basics
A Content Security Policy defines which resources are allowed to be loaded and executed on your webpage. It acts as a whitelist, explicitly stating which sources are trusted. Learn more about CSP basicsExample of a simple CSP policy
Content-Security-Policy: default-src 'self'; script-src 'self' https://website.com
Implementation Methods
1. HTTP Headers (Recommended)
The most secure and recommended way to implement CSP is through HTTP headers:Example of a comprehensive CSP policy in HTTP headers
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' ; img-src 'self';
Implementation in Nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' ; img-src 'self'";
Implementation in Apache
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://trusted.com; style-src 'self' 'unsafe-inline' https://trusted.com; img-src 'self' data: https://trusted.com; font-src 'self' https://trusted.com; connect-src 'self' https://api.trusted.com;";
Best Practice
Using HTTP headers ensures that the CSP is enforced before any content is loaded, providing maximum security coverage.
2. Meta Tags
CSP can also be implemented using HTML meta tags, though this method has limitations:Example of a CSP policy in meta tags with nonce
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSP Meta Tag Implementation -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://trusted.com">
<title>Your Website</title>
</head>
<body>
<script>
// Your inline script here
</script>
</body>
</html>
Advanced CSP Features
Nonces and Hashes
Nonces and hashes provide granular control over inline scripts and styles. Nonces are random values that must match between CSP and elements, while hashes are SHA-256/384/512 values of inline content.
Example of nonce and hash usage in CSP
Content-Security-Policy: script-src 'nonce-random123' 'sha256-hashvalue';
Strict Dynamic
The 'strict-dynamic' directive enhances security for dynamically loaded scripts. It allows trusted scripts to load other scripts, which is particularly useful for modern web applications. However, it requires careful implementation to avoid breaking functionality.
Common CSP Misconfigurations
Overly Permissive Policies
Common mistakes that weaken security include using 'unsafe-inline' too broadly, setting overly permissive default-src, and not properly restricting script-src directives.
Missing Critical Directives
Important directives often overlooked include base-uri (controls base tag behavior), form-action (controls form submissions), and frame-ancestors (controls embedding).
Limitations of Meta Tags
No Report-Only Mode
Meta tags don't support Content-Security-Policy-Report-Only, making it impossible to test policies without potentially breaking your site.
Limited Directive Support
Some directives are not supported in meta tags
- frame-ancestors directive is not supported
- sandbox directive is not supported
- report-uri directive is not supported
JavaScript Execution Timing
Browsers might execute JavaScript before processing the CSP when using meta tags, as the policy only takes effect after HTML parsing begins.
- Creates potential race conditions
- Reduces security effectiveness
- May allow XSS attacks to execute before policy enforcement
Security Risk
If an attacker manages to inject JavaScript before the CSP meta tag is processed, they could bypass the policy entirely. This creates a race condition vulnerability that doesn't exist with HTTP headers.
Using Both Methods Together
When both HTTP headers and meta tags are present, browsers will combine both policies using the most restrictive rules from each.Example of combining HTTP headers and meta tags
Content-Security-Policy: default-src 'self';
Example of a CSP policy in meta tags
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://website.com;">
Result
In this example, even though the meta tag allows 'self' and website.com, the final policy will only allow 'self' because the HTTP header is more restrictive. Resources from website.com will be blocked by the policy in the HTTP header.
Best Practices
Implementation Preference
Choose the most secure implementation method
- Always prefer HTTP headers for CSP implementation
- Only use meta tags when HTTP headers cannot be modified
- Test policies thoroughly using Report-Only mode before enforcement
- Use nonces and hashes instead of 'unsafe-inline' when possible
Validation and Monitoring
Ensure proper policy configuration and tracking
- Use our CSP Scanner to validate your policies
- Set up a CSP reporting endpoint to monitor violations
- Regularly review and update policies based on reports
- Monitor for false positives and adjust policies accordingly
Modern Security Features
Implement additional security headers
- Use Subresource Integrity (SRI) for external resources
- Implement Trusted Types for DOM manipulation
- Consider using Permissions Policy alongside CSP
Start monitoring your CSP policy
Join thousands of developers who trust CentralCSP to protect their websites.
Start with a 14 days free trialConclusion
While meta tags provide an alternative way to implement CSP, HTTP headers remain the recommended approach due to better feature support, earlier policy enforcement, and complete directive coverage. Only use meta tags when technical constraints prevent you from modifying HTTP headers. Remember to regularly review and update your CSP policies to maintain strong security while ensuring your website's functionality.