streamflow/docs/CSP_IMPLEMENTATION.md
2025-12-17 00:42:43 +00:00

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-src prevents 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:

  1. Total Violations - Overall security health
  2. By Directive - Which policies are triggering
  3. By Blocked URI - What resources are being blocked
  4. Trends - Increasing violations may indicate attack

Incident Response

High Violation Count:

  1. Check CSP Dashboard for patterns
  2. Identify blocked URIs
  3. Verify if legitimate or malicious
  4. Update policy if needed or investigate further

Suspicious Patterns:

  1. Multiple violations from same IP
  2. Violations targeting authentication pages
  3. 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:

  1. Report-only mode (current)
  2. Enforce with relaxed rules
  3. Tighten specific directives
  4. 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:

  1. Check browser console for CSP violations
  2. Temporarily disable CSP:
    contentSecurityPolicy: false
    
  3. Identify blocked resource
  4. 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:

  1. Identify pattern (same URI/directive)
  2. Fix underlying issue
  3. 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> tags
  • script-src-attr: Separate rules for event handlers
  • worker-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

Support

For CSP-related issues:

  1. Check CSP Dashboard at /security/csp
  2. Review browser console for violation details
  3. Query csp_violations table in database
  4. Check backend logs for CSP configuration errors

Status: Implemented and Active Mode: Report-Only (Development) | Enforcing (Production) Version: 1.0 Last Updated: 2024