Enhanced Content Security Policy (CSP) Configuration
XyPriss provides advanced Content Security Policy configuration with flexible directive support, allowing developers to create comprehensive security policies for their web applications.
Overview
The Helmet middleware in XyPriss now supports fully customizable CSP directives using a flexible Record<string, any> type, enabling any CSP directive to be configured with any value type.
Basic Configuration
Simple CSP Setup
import { createServer } from 'xypriss';
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
}
}
}
}
});
Advanced CSP with Multiple Sources
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
// Multiple source types
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
"'unsafe-inline'",
"'unsafe-eval'",
"https://cdn.example.com",
"https://api.stripe.com"
"https://api.nehonix.com"
],
styleSrc: [
"'self'",
"'unsafe-inline'",
"https://fonts.googleapis.com"
],
fontSrc: [
"'self'",
"https://fonts.gstatic.com",
"data:"
],
imgSrc: [
"'self'",
"data:",
"https:",
"blob:"
],
connectSrc: [
"'self'",
"https://api.example.com",
"wss://websocket.example.com"
],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
frameAncestors: ["'none'"],
upgradeInsecureRequests: []
}
}
}
}
});
Flexible Directive Types
String Directives
contentSecurityPolicy: {
directives: {
// Single string value
baseUri: "'self'",
// Multiple values as array
scriptSrc: ["'self'", "https://cdn.example.com"],
// Special CSP keywords
frameSrc: "'none'",
objectSrc: "'none'"
}
}
Array Directives
contentSecurityPolicy: {
directives: {
// Multiple sources
scriptSrc: [
"'self'",
"'unsafe-inline'",
"https://cdn.example.com",
"https://api.stripe.com"
],
// Mixed protocols and domains
connectSrc: [
"'self'",
"https://api.example.com",
"wss://websocket.example.com"
]
}
}
Special Directives
contentSecurityPolicy: {
directives: {
// Empty array for boolean directives
upgradeInsecureRequests: [],
// Block all
frameAncestors: "'none'",
// Allow all (not recommended)
imgSrc: ["*"],
// Data URLs
imgSrc: ["data:"],
// Blob URLs
imgSrc: ["blob:"]
}
}
Real-World Examples
E-commerce Application
const eCommerceApp = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
"'unsafe-inline'", // For inline event handlers
"https://js.stripe.com",
"https://cdn.example.com"
],
styleSrc: [
"'self'",
"'unsafe-inline'",
"https://fonts.googleapis.com"
],
fontSrc: [
"'self'",
"https://fonts.gstatic.com"
],
imgSrc: [
"'self'",
"data:",
"https:",
"blob:"
],
connectSrc: [
"'self'",
"https://api.stripe.com",
"https://api.example.com"
],
frameSrc: [
"https://js.stripe.com",
"https://www.youtube.com"
],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
frameAncestors: ["'none'"],
upgradeInsecureRequests: []
}
}
}
}
});
Single Page Application (SPA)
const spaApp = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
"'unsafe-eval'", // For webpack dev server
"https://cdn.jsdelivr.net"
],
styleSrc: [
"'self'",
"'unsafe-inline'",
"https://fonts.googleapis.com"
],
fontSrc: [
"'self'",
"https://fonts.gstatic.com",
"data:"
],
imgSrc: [
"'self'",
"data:",
"https:",
"blob:"
],
connectSrc: [
"'self'",
"https://api.example.com",
"wss://api.example.com"
],
workerSrc: ["'self'", "blob:"],
childSrc: ["'self'", "blob:"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
frameAncestors: ["'none'"]
}
}
}
}
});
API-Only Server
const apiServer = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'none'"],
scriptSrc: ["'none'"],
styleSrc: ["'none'"],
imgSrc: ["'none'"],
fontSrc: ["'none'"],
connectSrc: ["'none'"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
baseUri: ["'none'"],
formAction: ["'none'"],
frameAncestors: ["'none'"]
}
}
}
}
});
Development vs Production
const isProduction = process.env.NODE_ENV === 'production';
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: isProduction
? ["'self'", "https://cdn.example.com"]
: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
styleSrc: isProduction
? ["'self'", "https://fonts.googleapis.com"]
: ["'self'", "'unsafe-inline'"],
// ... other directives
}
}
}
}
});
CSP Nonces and Hashes
Nonce Support
// Generate nonce for each request
app.use((req, res, next) => {
res.locals.nonce = crypto.randomBytes(16).toString('base64');
next();
});
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
scriptSrc: [
"'self'",
(req, res) => `'nonce-${res.locals.nonce}'`
]
}
}
}
}
});
Hash Support
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
scriptSrc: [
"'self'",
"'sha256-abc123...'" // Inline script hash
]
}
}
}
}
});
Advanced CSP Features
Report-Only Mode
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
reportOnly: true, // Don't enforce, just report
directives: {
// Your directives here
},
reportUri: "/csp-report"
}
}
}
});
// Handle CSP violation reports
app.post('/csp-report', (req, res) => {
console.log('CSP Violation:', req.body);
res.status(204).end();
});
Custom Report URI
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
reportUri: "/api/security/csp-violation"
}
}
}
}
});
CSP Testing and Debugging
Browser Developer Tools
- Open Developer Tools (F12)
- Go to Console tab
- Look for CSP violation messages
- Check Network tab for blocked resources
Testing Tools
# Test CSP with curl
curl -H "User-Agent: Mozilla/5.0..." \
-H "Sec-Fetch-Dest: script" \
http://localhost:3000
# Check CSP headers
curl -I http://localhost:3000
Common Issues
Inline Scripts Blocked
// ❌ This will be blocked
<script>console.log('hello');</script>
// ✅ Add 'unsafe-inline' or use nonce/hash
contentSecurityPolicy: {
directives: {
scriptSrc: ["'self'", "'unsafe-inline'"]
}
}
External Resources Blocked
// ❌ This will be blocked
<script src="https://cdn.example.com/script.js"></script>
// ✅ Add domain to CSP
contentSecurityPolicy: {
directives: {
scriptSrc: ["'self'", "https://cdn.example.com"]
}
}
Inline Styles Blocked
// ❌ This will be blocked
<style>body { color: red; }</style>
// ✅ Add 'unsafe-inline' for styles
contentSecurityPolicy: {
directives: {
styleSrc: ["'self'", "'unsafe-inline'"]
}
}
Performance Considerations
- Minimal overhead: CSP headers are static and cached
- Browser optimization: Modern browsers optimize CSP parsing
- CDN friendly: CSP works well with CDNs and edge networks
- Incremental adoption: Start with basic policies and expand gradually
Security Best Practices
- Principle of least privilege: Only allow necessary sources
- Avoid 'unsafe-inline': Use nonces or hashes instead
- Avoid 'unsafe-eval': Avoid eval() and similar functions
- Use HTTPS: Always prefer HTTPS sources
- Regular audits: Review and update CSP regularly
- Monitor violations: Set up reporting and monitoring
- Test thoroughly: Test in all browsers and scenarios
Migration Guide
From Basic Helmet
// Before: Basic helmet
const app = createServer({
security: {
helmet: true
}
});
// After: Custom CSP
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'"]
}
}
}
}
});
From Express CSP Middleware
// Before: express-csp
app.use(csp({
directives: {
defaultSrc: "'self'",
scriptSrc: ["'self'", "'unsafe-inline'"]
}
}));
// After: XyPriss CSP
const app = createServer({
security: {
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"]
}
}
}
}
});
This enhanced CSP configuration provides developers with complete control over their application's security policies while maintaining ease of use and flexibility.