This document outlines the comprehensive security measures implemented in the Weather App to protect against common web vulnerabilities.
- Purpose: Prevents Cross-Site Scripting (XSS) attacks by controlling which resources can be loaded
- Configuration:
- Development: Allows inline scripts and styles for development convenience
- Production: Restricts to trusted sources only, includes Vercel domains
- Key Directives:
default-src 'self'
- Only allow resources from same originscript-src 'self'
- Only allow scripts from same originframe-ancestors 'none'
- Prevent embedding in iframesobject-src 'none'
- Block plugins and objects
- Value:
DENY
- Purpose: Prevents clickjacking attacks by blocking iframe embedding
- Value:
nosniff
- Purpose: Prevents MIME type sniffing attacks
- Value:
1; mode=block
- Purpose: Additional XSS protection layer for older browsers
- Value:
strict-origin-when-cross-origin
- Purpose: Controls referrer information sent with requests
- Value: Restricts access to sensitive browser features
- Blocked Features: Camera, microphone, geolocation, payment, USB, sensors
- Purpose: Prevents unauthorized access to device capabilities
- Value:
max-age=31536000; includeSubDomains; preload
- Purpose: Enforces HTTPS connections for 1 year
- Value:
off
- Purpose: Disables DNS prefetching for privacy
Security headers are automatically applied via vercel.json
:
{
"headers": [
{
"source": "/(.*)",
"headers": [
// All security headers are applied here
]
}
]
}
Security headers are applied via Express middleware in server.ts
:
// Security headers middleware
app.use((req, res, next) => {
// Apply all security headers from configuration
Object.entries(SECURITY_CONFIG.HEADERS).forEach(([key, value]) => {
res.setHeader(key, value);
});
// Set Content Security Policy based on environment
const csp = buildCSP(isProduction ? 'production' : 'development');
res.setHeader('Content-Security-Policy', csp);
next();
});
The Weather App includes a comprehensive security testing script to validate that all security headers are properly configured and working.
# Test security headers on default port (5173)
npm run test:security
# Test security headers on custom port
npx tsx scripts/test-security.ts 3000
# Test security headers directly with tsx
tsx scripts/test-security.ts [port]
The security test script validates all 8 security headers:
Critical Headers (π¨)
- X-Content-Type-Options:
nosniff
- Prevents MIME type sniffing - X-Frame-Options:
DENY
- Prevents clickjacking attacks - X-XSS-Protection:
1; mode=block
- Enables XSS protection - Strict-Transport-Security:
max-age=31536000; includeSubDomains; preload
- Enforces HTTPS - Content-Security-Policy: Must be set (content varies by environment)
Important Headers (βΉοΈ)
- Referrer-Policy:
strict-origin-when-cross-origin
- Controls referrer information - Permissions-Policy: Restricts access to sensitive browser features
- X-DNS-Prefetch-Control:
off
- Disables DNS prefetching
- Development server must be running (
npm run dev
) - Server must be accessible on the specified port
- All security headers must be properly configured
π Security Headers Test Results
================================
β
Passed: 8
β Failed: 0
β
π¨ X-Content-Type-Options
Description: Prevents MIME type sniffing
β
π¨ X-Frame-Options
Description: Prevents clickjacking attacks
β
π¨ X-XSS-Protection
Description: Enables XSS protection
β
βΉοΈ Referrer-Policy
Description: Controls referrer information
β
βΉοΈ Permissions-Policy
Description: Restricts browser features
β
βΉοΈ X-DNS-Prefetch-Control
Description: Disables DNS prefetching
β
π¨ Strict-Transport-Security
Description: Enforces HTTPS
β
π¨ Content-Security-Policy
Description: Defines content security policy
π All security headers are properly configured!
The script provides:
- β Pass/Fail status for each header
- π¨ Critical vs βΉοΈ informational header indicators
- Detailed descriptions of each security measure
- Summary of passed/failed tests
- Exit code 1 if critical headers fail
Check headers using browser DevTools or curl:
curl -I http://localhost:5173
All requests should include:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()
X-DNS-Prefetch-Control: off
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: [environment-specific policy]
Centralized security configuration with:
- CSP policies for different environments
- Security header definitions
- Validation utilities
- Future CORS and rate limiting configurations
Testing utilities for:
- Automated header validation
- Security compliance checking
- Development debugging
- Development: More permissive CSP for debugging
- Production: Strict CSP with only necessary exceptions
- Weather API calls to
api.openweathermap.org
are explicitly allowed - Vercel domains are whitelisted for production features
- Rate limiting implementation
- CORS configuration if needed
- Additional security middleware (helmet, etc.)
Regularly check security headers using:
- Browser DevTools Network tab
- Security testing tools (OWASP ZAP, Burp Suite)
- Online security header checkers
- Automated testing in CI/CD pipeline
- npm run test:security - Built-in security validation
If you see CSP violations in the browser console, check these common issues:
- Error:
Refused to load stylesheet from 'https://fonts.googleapis.com'
- Solution: Ensure CSP includes
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com
- Current Status: β Fixed - Google Fonts are properly allowed
- Error:
Refused to execute inline script
- Solution: Add external domain to
script-src
directive if needed - Current Status: β Configured - Only trusted sources allowed
- Error:
Refused to load image from external domain
- Solution: Check
img-src
directive includes necessary domains - Current Status: β
Configured -
img-src 'self' data: https:
allows external images
- Check Browser Console: Look for CSP violation messages
- Verify Current CSP: Use
curl -I | grep Content-Security-Policy
- Test Security Headers: Run
npm run test:security
- Update Configuration: Modify
src/config/security.ts
as needed - Restart Server: Changes require server restart to take effect
When adding new external resources (CDNs, APIs, etc.):
- Identify the resource type (script, style, font, image, etc.)
- Add to appropriate CSP directive in
src/config/security.ts
- Include in both development and production configurations
- Test thoroughly to ensure no CSP violations
- Document the change in this file
- WebSocket Connections:
ws://localhost:*
andws://127.0.0.1:*
for Vite HMR - Inline Scripts:
'unsafe-inline'
for development convenience - Eval:
'unsafe-eval'
for Vite's development features
- No WebSocket Connections: Not needed for production
- Stricter Scripts: Limited to trusted domains only
- HTTPS Only:
upgrade-insecure-requests
enforced - Vercel Domains: Only whitelisted production domains
- Development: Needs flexibility for hot reloading and debugging
- Production: Maximum security with minimal external dependencies
- HMR: WebSocket connections only needed during development
- Security: Production maintains strict CSP without development conveniences
- Security headers are applied at the server level
- CSP policies are environment-specific
- All critical security headers are marked as required
- Regular security audits are recommended
- Keep dependencies updated for security patches
- Use the built-in security test script for validation
- Start development server:
npm run dev
- Test security headers:
npm run test:security
- Verify all headers pass: Should show 8/8 passed
- Deploy to production: Security headers automatically applied via Vercel