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 #

  1. Open Developer Tools (F12)
  2. Go to Console tab
  3. Look for CSP violation messages
  4. 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 #

  1. Principle of least privilege: Only allow necessary sources
  2. Avoid 'unsafe-inline': Use nonces or hashes instead
  3. Avoid 'unsafe-eval': Avoid eval() and similar functions
  4. Use HTTPS: Always prefer HTTPS sources
  5. Regular audits: Review and update CSP regularly
  6. Monitor violations: Set up reporting and monitoring
  7. 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.