This page demonstrates a comprehensive, secure Content Security Policy (CSP) implementation that effectively protects against various web vulnerabilities, particularly those related to iframes and content embedding. Pink Sock should not detect any security issues with this implementation.
Secure Example
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; font-src 'self'; frame-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; report-uri /csp-report">
Security Features Explained
Default Deny Approach
This CSP follows the principle of "default deny" with default-src 'none', which means nothing is allowed unless explicitly permitted. This ensures that any content types not specifically mentioned are blocked.
Critical CSP Directives
| Directive | Value | Security Benefit |
|---|---|---|
| script-src | 'self' | Only allows scripts from the same origin, blocking inline scripts and third-party scripts |
| frame-src | 'self' | Only allows iframes loading content from the same origin |
| frame-ancestors | 'self' | Only allows the page to be framed by pages from the same origin, preventing clickjacking |
| object-src | 'none' | Blocks all plugins and embedded objects, which can be security risks |
| base-uri | 'self' | Prevents attackers from changing the base URL, which could redirect relative paths |
| form-action | 'self' | Only allows forms to submit to the same origin, preventing cross-site data leakage |
Iframe Sandbox Security
The iframe in this example includes the minimal sandboxing needed:
sandbox="allow-scripts"- Permits JavaScript execution while maintaining other security restrictions- Omits
allow-formsto prevent the risky combination withallow-scripts - Omits
allow-same-originwhich would defeat sandbox protections when combined with scripts - Omits
allow-top-navigationto prevent navigation-based attacks
This configuration applies the principle of least privilege to iframe permissions.
CSP Violation Reporting
The policy includes a report-uri directive, which sends violation reports to a specified endpoint. This provides valuable information about potential attacks and unintended CSP violations for continuous security improvement.
No 'unsafe-inline' or 'unsafe-eval'
The policy does not include the dangerous 'unsafe-inline' or 'unsafe-eval' directives, which would weaken protection against XSS attacks. Instead, only same-origin scripts are allowed.
Defense in Depth Strategy
This CSP is part of a defense in depth strategy that includes:
- Content Security Policy for broad protection
- Proper iframe sandboxing for embedded content
- Restricted resource loading patterns
- Careful control of script execution contexts
Implementation Best Practices
Incremental Deployment
When implementing a strict CSP like this one, consider these steps:
- Start with Report-Only Mode:
Content-Security-Policy-Report-Only: default-src 'none'; script-src 'self';...
- Collect and analyze violation reports
- Adjust policy to address legitimate use cases
- Progressively tighten the policy
- Move from report-only to enforcement mode
Handling Legacy Requirements
If inline scripts or third-party resources are absolutely required:
- Use nonces for necessary inline scripts:
script-src 'self' 'nonce-RandomValue' - Use hashes for static inline code:
script-src 'self' 'sha256-HashValue' - Explicitly whitelist trusted external domains rather than allowing all
- Use
strict-dynamicfor script loading in modern browsers
CSP Header vs. Meta Tag
While this example uses a meta tag, the preferred approach is to deliver CSP via HTTP headers:
Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self';...
HTTP headers cannot be bypassed if an attacker manages to inject content into the page.
Additional Security Headers
For maximum security, complement CSP with these headers:
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()
Strict-Transport-Security: max-age=31536000; includeSubDomains