This document outlines the production-safe security headers and CORS configuration implemented for the Callora Backend.
The application implements comprehensive security headers and CORS policies that adapt based on the environment (development vs production) to provide both security and developer ergonomics.
Production:
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self';
font-src 'self';
object-src 'none';
media-src 'self';
frame-src 'none';
Development:
- Same as production but allows
'unsafe-inline'for styles to support hot reload - Includes
ws:andwss:inconnect-srcfor WebSocket connections
Production:
max-age=31536000(1 year)includeSubDomainspreload
Development:
- Disabled (no HSTS header)
- X-Frame-Options:
DENY - X-Content-Type-Options:
nosniff - Referrer-Policy:
strict-origin-when-cross-origin - Cross-Origin Embedder Policy:
require-corp(production only) - X-Powered-By: Hidden in production
Production:
- Strict origin validation against
CORS_ALLOWED_ORIGINS - Logs blocked attempts for security monitoring
- Preflight cache: 10 minutes (
max-age=600) - Warning if no origins configured
Development:
- Allows any
localhost:*origin for ergonomics - Preflight cache: 24 hours (
max-age=86400) - More permissive for local development
Content-Type
Authorization
x-admin-api-key
x-user-id
x-request-id
GET, POST, PATCH, DELETE, OPTIONS
- Enabled (
credentials: true) for authenticated requests
NODE_ENV=production
CORS_ALLOWED_ORIGINS=https://app.example.com,https://admin.example.comNODE_ENV=development
CORS_ALLOWED_ORIGINS=http://localhost:5173- HTTPS Required: HSTS is only enabled in production with HTTPS
- Origin Allowlisting: Only explicitly configured origins are allowed
- Monitoring: Blocked CORS attempts are logged
- Cache Duration: Shorter preflight cache for security
- Information Disclosure: Server information headers are hidden
- Localhost Support: Any localhost port is allowed
- Relaxed CSP: Allows inline styles for development tools
- Longer Cache: Reduces preflight requests during development
- WebSocket Support: Allows WebSocket connections for hot reload
- Location:
src/__tests__/security-headers.test.ts - Covers header presence and content validation
- Tests environment-specific behavior
- Validates CORS origin handling
- Location:
tests/integration/security-headers.integration.test.ts - Tests real HTTP requests with security headers
- Validates production vs development behavior
- Performance and reliability testing
- Set
NODE_ENV=productionin production - Configure
CORS_ALLOWED_ORIGINSwith your frontend domains - Ensure HTTPS is enabled for HSTS to work
- Monitor logs for blocked CORS attempts
- Set
NODE_ENV=development(or don't set, defaults to development) - No additional configuration needed for localhost
- Existing
CORS_ALLOWED_ORIGINSwill still work
| Header | Production | Development | Purpose |
|---|---|---|---|
| Content-Security-Policy | Strict | Relaxed | Prevent XSS, data injection |
| Strict-Transport-Security | Enabled | Disabled | Enforce HTTPS |
| X-Frame-Options | DENY | DENY | Prevent clickjacking |
| X-Content-Type-Options | nosniff | nosniff | Prevent MIME sniffing |
| Referrer-Policy | strict-origin-when-cross-origin | strict-origin-when-cross-origin | Control referrer leakage |
| Cross-Origin-Embedder-Policy | require-corp | disabled | Control cross-origin embedding |
| X-Powered-By | hidden | visible | Prevent information disclosure |
| Setting | Production | Development |
|---|---|---|
| Origin Validation | Strict (allowlist) | Permissive (localhost + allowlist) |
| Max-Age | 600s (10 min) | 86400s (24 hours) |
| Credentials | Enabled | Enabled |
| Logging | Blocked attempts logged | No logging |
# Environment variables
NODE_ENV=production
CORS_ALLOWED_ORIGINS=https://yourapp.com,https://admin.yourapp.com
# Nginx/Apache proxy configuration (if applicable)
# Ensure these headers are passed through:
# - X-Forwarded-Proto
# - X-Forwarded-Host
# - X-Forwarded-For- CORS Blocks: Monitor console logs for "CORS blocked origin" messages
- HSTS Compliance: Ensure your domain is in HSTS preload lists if needed
- CSP Violations: Monitor browser console for CSP violations
- Security Headers: Use tools like securityheaders.com to validate configuration
- Multiple CORS blocks from same origin may indicate attack attempts
- Unexpected origins in logs may require allowlist updates
- Missing security headers may indicate configuration issues
-
CORS Errors in Production
- Verify
CORS_ALLOWED_ORIGINSis set correctly - Check that origins include protocol (https://)
- Ensure no trailing slashes in origins
- Verify
-
HSTS Not Working
- Verify
NODE_ENV=production - Ensure site is served over HTTPS
- Check that HSTS header is present in responses
- Verify
-
CSP Violations
- Check browser console for CSP errors
- Update CSP directives if legitimate resources are blocked
- Consider nonce-based CSP for dynamic content
-
Development Issues
- Set
NODE_ENV=developmentfor relaxed policies - Ensure localhost origins are used for local development
- Check that WebSocket connections are allowed
- Set
- Regular Reviews: Periodically review and update allowlists
- Monitoring: Set up alerts for security events
- Testing: Test configuration in staging before production
- Documentation: Keep this documentation updated with changes
- Compliance: Ensure compliance with organizational security policies
helmet: ^8.1.0- Security header middlewarecors: ^2.8.6- CORS middlewareexpress: ^4.18.2- Web framework
- v1.0.0 - Initial implementation with production-safe defaults
- Environment-based configuration
- Comprehensive CSP and HSTS support
- Enhanced CORS with logging and validation