Security is one of the most critical aspects of modern web development. Even if your code is correct, attackers may exploit vulnerabilities like Cross-Site Scripting (XSS) or Clickjacking. Thatβs where Content Security Policy (CSP) comes in.
This blog covers:
β
 What CSP is & how it works
β
 All major directives (default-src, script-src, img-src, etc.) explained in detail
β
 Real-world examples
β
 Best practices & common pitfalls
Letβs dive in. π₯
βοΈ What is CSP & Why Do We Need It?
- Content Security Policy (CSP) is an HTTP response header that defines where browsers can load resources (scripts, images, styles, fonts, iframes, workers, etc.) from.
- Its main purpose: prevent XSS attacks by restricting execution of malicious scripts.
- Without CSP, if an attacker injects a script into your page, the browser executes it blindly. With CSP, you can whitelist only trusted domains, blocking everything else.
Example CSP header:
Content-Security-Policy: default-src 'self'; img-src https://cdn.example.com; script-src 'self' https://apis.google.com;
This means:
- By default, only load resources from the same origin ('self').
- Allow images from cdn.example.com.
- Allow scripts from self and Google APIs.
β οΈ Important:
Ifdefault-srcis missing, everything is allowed, weakening your CSP.
π Important Directives
Hereβs a breakdown of commonly used CSP directives:
  
  
  π default-src
The fallback for all other directives (if they are not explicitly defined).
Content-Security-Policy: default-src 'self';
If script-src or style-src is missing, browsers fall back to default-src. β
  
  
  π script-src
Defines where JavaScript can be loaded from.
Content-Security-Policy: script-src 'self' https://apis.google.com;
- 
Special values: - 
'self': allow only current domain
- 
'unsafe-eval': alloweval()usage (β οΈ dangerous)
- 
'unsafe-inline': allow inline scripts (β οΈ not recommended)
 
- 
- 
Better options: - Nonce β Random value per request:
 <script nonce="abc123">console.log("Safe!");</script>With CSP: 
 Content-Security-Policy: script-src 'self' 'nonce-abc123';- Hash β Allow only exact inline script:
 <script>alert("hello")</script>With CSP: 
 Content-Security-Policy: script-src 'self' 'sha256-XYZhashHere...';
β
 Nonce & Hash are safer than 'unsafe-inline'.
  
  
  π¨ style-src
Controls where CSS can be loaded from.
Content-Security-Policy: style-src 'self' https://fonts.googleapis.com;
β οΈ Using 'unsafe-inline' allows inline styles β risky.
π Instead:
- Use nonce or hashes for dynamic styles.
- Example:
  <style nonce="abc123">.btn { color: red; }</style>
  
  
  πΌοΈ img-src
Defines allowed image sources.
Content-Security-Policy: img-src 'self' https://cdn.example.com data:;
π data: allows base64-encoded images.
  
  
  π font-src
Controls allowed font sources.
Content-Security-Policy: font-src 'self' https://fonts.gstatic.com;
  
  
  π connect-src
Defines where AJAX/fetch/WebSocket connections can be made.
Content-Security-Policy: connect-src 'self' https://api.example.com;
  
  
  π΅ media-src
Specifies allowed sources for <audio> and <video>.
Content-Security-Policy: media-src 'self' https://media.example.com;
  
  
  ποΈ frame-src vs frame-ancestors
- 
frame-src: Controls what your app can embed in an<iframe>.
  Content-Security-Policy: frame-src https://www.youtube.com;
- 
frame-ancestors: Controls who can embed your site.
  Content-Security-Policy: frame-ancestors 'none';
β
 Use frame-ancestors to prevent clickjacking.
  
  
  π§© worker-src
Defines allowed sources for Web Workers & Service Workers.
- Web Workers: Run scripts in a separate thread (background tasks).
- Service Workers: Proxy requests for offline support / caching.
Content-Security-Policy: worker-src 'self' https://cdn.example.com;
  
  
  π object-src
Restricts plugins like Flash/Silverlight (legacy). Best to set 'none'.
Content-Security-Policy: object-src 'none';
π Reporting with CSP
Instead of enforcing, you can test with reporting only:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint;
This way, violations are logged but not blocked. Useful before rollout.
π‘ Real-World Example
Imagine your webapp loads:
- Scripts from your domain + Google APIs
- Styles from your domain + Google Fonts
- Images from CDN
CSP could look like:
Content-Security-Policy: default-src 'self'; script-src 'self' https://apis.google.com; style-src 'self' https://fonts.googleapis.com; img-src 'self' https://cdn.example.com; connect-src 'self' https://api.myapp.com; object-src 'none'; frame-ancestors 'none'
This protects you from attackers injecting malicious scripts/images from untrusted domains.
π¨ Common CSP Issues Developers Face
- β Images not loading β Forgot img-srcdomain.
- β Fonts breaking β Missing font-src.
- β Videos not playing β media-srcmissing.
- β API calls failing β Missing connect-src.
- β App not embeddable β Strict frame-ancestors.
π If your frontend/backend look fine but still break, check CSP first.
β Best Practices
- Always define a strict default-src.
- Avoid 'unsafe-inline'and'unsafe-eval'unless absolutely necessary β use nonces or hashes.
- Use 'self'wherever possible.
- Test with Content-Security-Policy-Report-Onlybefore enforcing.
π Conclusion
CSP is not just another headerβitβs a powerful security shield π‘οΈ for your apps.
The right configuration prevents XSS, clickjacking, and data injection while keeping performance intact.
π The bottom line: CSP = Control + Security + Peace of Mind.
 
 
              
 
    
Top comments (0)