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.