13 KiB
Content Security Policy (CSP) Implementation Guide
Overview
This document details the comprehensive Content Security Policy (CSP) implementation for StreamFlow, providing defense-in-depth protection against Cross-Site Scripting (XSS), code injection, and other client-side attacks.
What is Content Security Policy?
Content Security Policy (CSP) is a security standard that helps prevent XSS attacks, clickjacking, and other code injection attacks by controlling which resources browsers are allowed to load. It acts as an allow list, telling browsers which sources are trusted for scripts, styles, images, and other resources.
Implementation
1. Backend CSP Configuration
File: backend/server.js
The CSP is configured using helmet middleware with environment-aware settings:
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
"'unsafe-inline'", // Required for React/Vite
"'unsafe-eval'", // Required for React DevTools
"https://www.gstatic.com" // Google Cast SDK
],
styleSrc: [
"'self'",
"'unsafe-inline'", // Required for MUI
"https://fonts.googleapis.com"
],
fontSrc: [
"'self'",
"data:",
"https://fonts.gstatic.com"
],
imgSrc: [
"'self'",
"data:",
"blob:",
"https:",
"http:" // External logos
],
mediaSrc: [
"'self'",
"blob:",
"data:",
"mediastream:",
"https:",
"http:",
"*" // IPTV streams
],
connectSrc: [
"'self'",
"https:",
"http:",
"ws:",
"wss:", // WebSocket
"blob:",
"*" // External APIs
],
frameSrc: [
"'self'",
"https://www.youtube.com",
"https://player.vimeo.com"
],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
frameAncestors: ["'self'"],
upgradeInsecureRequests: isProduction ? [] : null
},
reportOnly: !isProduction,
useDefaults: false
}
}));
2. CSP Violation Reporting
File: backend/routes/csp.js
A dedicated API endpoint collects and stores CSP violation reports:
Endpoints
POST /api/csp/report (No auth required)
- Receives CSP violation reports from browsers
- Stores violations in database
- Logs violations for analysis
GET /api/csp/violations (Admin only)
- Retrieves list of CSP violations
- Supports pagination
GET /api/csp/stats (Admin only)
- Returns violation statistics
- Groups by directive and blocked URI
- Shows trends over time
DELETE /api/csp/violations (Admin only)
- Clears old violation reports
- Configurable retention period
GET /api/csp/policy (Authenticated users)
- Returns current CSP policy configuration
- Shows enforcement mode (enforce vs report-only)
3. Database Schema
CREATE TABLE IF NOT EXISTS csp_violations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
document_uri TEXT,
violated_directive TEXT,
blocked_uri TEXT,
source_file TEXT,
line_number INTEGER,
column_number INTEGER,
user_agent TEXT,
ip_address TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
4. CSP Dashboard UI
File: frontend/src/components/CSPDashboard.jsx
Admin interface for monitoring CSP violations:
Features:
- Real-time CSP policy status
- Violation count and trends
- Detailed violation reports
- Statistics by directive and URI
- Current policy viewer
- Violation cleanup tools
- Search and filter capabilities
Access: Available at /security/csp (admin only)
CSP Directives Explained
Core Directives
default-src: ['self']
- Fallback for other directives
- Only allows resources from same origin
script-src
- Controls JavaScript execution
'self': Same-origin scripts'unsafe-inline': Inline scripts (required for React)'unsafe-eval': eval() usage (required for some libraries)https://www.gstatic.com: Google Cast SDK
style-src
- Controls CSS loading
'self': Same-origin styles'unsafe-inline': Inline styles (required for MUI)https://fonts.googleapis.com: Google Fonts
img-src
- Controls image loading
- Allows data: URIs for inline images
- Allows external HTTPS/HTTP for channel logos
media-src
- Controls audio/video loading
*: Allows all sources (required for IPTV streams)- Includes blob: and mediastream: for recordings
connect-src
- Controls AJAX, WebSocket, EventSource
*: Allows all (required for streaming APIs)
object-src: ['none']
- Blocks plugins (Flash, Java)
- Security best practice
frame-src
- Controls iframe embedding
- Allows YouTube and Vimeo players
base-uri: ['self']
- Prevents
<base>tag manipulation
form-action: ['self']
- Prevents form submission to external sites
frame-ancestors: ['self']
- Prevents clickjacking
- Controls who can embed this site
Environment-Specific
upgrade-insecure-requests
- Production only
- Automatically upgrades HTTP to HTTPS
Report-Only Mode
- Development: Report violations but don't block
- Production: Enforce policy and block violations
Attack Prevention
XSS Prevention
Inline Script Injection:
<!-- This would be blocked -->
<script>alert('XSS')</script>
External Malicious Script:
<!-- This would be blocked -->
<script src="https://evil.com/malware.js"></script>
Event Handler Injection:
<!-- This would be blocked in strict CSP -->
<img src="x" onerror="alert('XSS')">
Code Injection Prevention
eval() Restrictions:
- Limited to trusted sources only
- Blocks arbitrary code execution
Data Exfiltration:
connect-srcprevents unauthorized API calls- Blocks data theft to attacker-controlled servers
Clickjacking Prevention
frame-ancestors: ['self']:
- Prevents embedding in malicious iframes
- Protects against UI redress attacks
Monitoring & Response
Violation Reports
CSP violations are automatically reported to /api/csp/report:
Example Violation:
{
"csp-report": {
"document-uri": "https://streamflow.com/",
"violated-directive": "script-src 'self'",
"blocked-uri": "https://malicious.com/evil.js",
"source-file": "https://streamflow.com/",
"line-number": 42,
"column-number": 8
}
}
Dashboard Metrics
Key Indicators:
- Total Violations - Overall security health
- By Directive - Which policies are triggering
- By Blocked URI - What resources are being blocked
- Trends - Increasing violations may indicate attack
Incident Response
High Violation Count:
- Check CSP Dashboard for patterns
- Identify blocked URIs
- Verify if legitimate or malicious
- Update policy if needed or investigate further
Suspicious Patterns:
- Multiple violations from same IP
- Violations targeting authentication pages
- Unusual blocked URIs (data exfiltration domains)
Configuration
Environment Variables
# CSP Mode
NODE_ENV=production # Enforce CSP
NODE_ENV=development # Report-only CSP
Customizing CSP
Adding Trusted Domain:
scriptSrc: [
"'self'",
"https://trusted-cdn.com" // Add here
]
Relaxing for Development:
contentSecurityPolicy: process.env.NODE_ENV === 'development' ? false : {
// ... policy
}
Nonce Support
The server generates unique nonces for inline scripts:
// Server-side
res.locals.nonce = crypto.randomBytes(16).toString('base64');
// Client-side
<script nonce="${nonce}">
// Inline code
</script>
Browser Compatibility
Supported Browsers
- ✅ Chrome 25+
- ✅ Firefox 23+
- ✅ Safari 7+
- ✅ Edge 12+
- ✅ Opera 15+
Fallback Behavior
Older browsers ignore CSP headers:
- No breaking changes
- App functions normally
- No CSP protection (but input validation still active)
Testing
Manual Testing
1. Test CSP Enforcement:
// Open browser console
eval('alert("CSP Test")');
// Should be blocked in production
2. Inject External Script:
const script = document.createElement('script');
script.src = 'https://external-domain.com/test.js';
document.body.appendChild(script);
// Should be blocked and reported
3. Check Violation Reports:
curl -H "Authorization: Bearer TOKEN" \
http://localhost:12345/api/csp/violations
Automated Testing
Expect CSP Header:
describe('CSP Headers', () => {
it('should include Content-Security-Policy header', async () => {
const response = await fetch('/');
expect(response.headers.get('content-security-policy')).toBeTruthy();
});
});
Verify Report-Only Mode:
it('should be report-only in development', () => {
if (process.env.NODE_ENV !== 'production') {
expect(headers.get('content-security-policy-report-only')).toBeTruthy();
}
});
Best Practices
1. Start with Report-Only
contentSecurityPolicy: {
reportOnly: true,
// ... directives
}
Monitor violations for 1-2 weeks before enforcing.
2. Minimize 'unsafe-inline'
Current implementation requires 'unsafe-inline' for React and MUI. Future improvements:
- Use nonces for all inline scripts
- Extract inline styles to external files
- Use CSS-in-JS with nonce support
3. Regular Review
- Weekly: Review violation reports
- Monthly: Update CSP based on patterns
- Quarterly: Remove unused directives
4. Gradual Tightening
Start permissive, gradually restrict:
- Report-only mode (current)
- Enforce with relaxed rules
- Tighten specific directives
- Remove 'unsafe-' directives
5. Document Exceptions
Every 'unsafe-*' or wildcard should have a comment:
scriptSrc: [
"'unsafe-inline'", // TODO: Remove after migrating to nonces
"'unsafe-eval'" // Required by React DevTools in dev mode
]
Deployment Checklist
- Test CSP in staging environment
- Monitor violation reports for 1-2 weeks
- Verify legitimate app functionality not blocked
- Switch from report-only to enforce mode
- Update documentation with any policy changes
- Set up alerts for violation spikes
- Train team on CSP dashboard usage
Troubleshooting
Issue: App not loading
Symptom: Blank page, scripts not executing
Solution:
- Check browser console for CSP violations
- Temporarily disable CSP:
contentSecurityPolicy: false - Identify blocked resource
- Add to appropriate directive
Issue: Inline styles blocked
Symptom: App has no styling
Solution:
Add 'unsafe-inline' to style-src (already included)
Issue: External resources blocked
Symptom: Images, videos, or streams not loading
Solution: Verify source in CSP violations, add domain if legitimate
Issue: Too many violation reports
Symptom: Database filling up, performance impact
Solution:
- Identify pattern (same URI/directive)
- Fix underlying issue
- Clear old reports:
curl -X DELETE -H "Authorization: Bearer TOKEN" \ "http://localhost:12345/api/csp/violations?days=7"
Performance Impact
Header Overhead:
- ~500 bytes per response
- Minimal impact on bandwidth
Browser Processing:
- Negligible CPU usage
- CSP checks are highly optimized
Violation Reporting:
- Async, doesn't block app
- Configurable rate limiting possible
Future Enhancements
1. Nonce-based Scripts
Replace 'unsafe-inline' with nonces:
scriptSrc: [
"'self'",
(req, res) => `'nonce-${res.locals.nonce}'`
]
2. Strict Dynamic
scriptSrc: ["'strict-dynamic'"]
Allows dynamically loaded scripts without wildcards.
3. Trusted Types
Prevent DOM XSS:
require-trusted-types-for 'script';
4. CSP Level 3 Features
script-src-elem: Separate rules for<script>tagsscript-src-attr: Separate rules for event handlersworker-src: Control Web Workers
5. Subresource Integrity (SRI)
Add integrity checks for external resources:
<script
src="https://cdn.com/lib.js"
integrity="sha384-..."
crossorigin="anonymous"
></script>
References
- MDN: Content Security Policy
- CSP Evaluator
- CSP Cheat Sheet
- report-uri.com - CSP reporting service
Support
For CSP-related issues:
- Check CSP Dashboard at
/security/csp - Review browser console for violation details
- Query
csp_violationstable in database - Check backend logs for CSP configuration errors
Status: ✅ Implemented and Active Mode: Report-Only (Development) | Enforcing (Production) Version: 1.0 Last Updated: 2024