-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
🛡️ HIGH: Missing Security Headers - Vulnerability to Common Web Attacks
Problem Description
The NSX application is missing essential security headers that protect against common web vulnerabilities. Currently, the Express server only disables the x-powered-by header but lacks comprehensive security middleware.
Current state:
// server/index.ts:34
app.disable('x-powered-by')
// Missing: Security headers, CSRF protection, etc.Why This Is Dangerous
Missing security headers expose the application to:
- XSS Attacks: No Content Security Policy (CSP) to prevent script injection
- Clickjacking: No X-Frame-Options to prevent iframe embedding
- MIME Sniffing: No X-Content-Type-Options to prevent MIME confusion
- Information Disclosure: Server version and technology stack exposed
- HTTPS Issues: No Strict-Transport-Security for HTTPS enforcement
- Referrer Leakage: No Referrer-Policy to control referrer information
Current Impact
- Severity: High
- Attack Vectors: XSS, Clickjacking, MIME confusion, Information disclosure
- Risk Level: High - Easy to exploit
Comprehensive Solution
1. Install Security Dependencies
pnpm add helmet
pnpm add -D @types/helmet2. Implement Helmet.js Security Headers
// server/index.ts
import helmet from 'helmet'
// Basic security headers
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "https:"],
scriptSrc: ["'self'"],
connectSrc: ["'self'"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
},
crossOriginEmbedderPolicy: false, // Disable if causing issues with external resources
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}))
// Additional security headers
app.use(helmet.referrerPolicy({ policy: 'strict-origin-when-cross-origin' }))
app.use(helmet.noSniff())
app.use(helmet.frameguard({ action: 'deny' }))3. Environment-Specific Configuration
// server/lib/security.ts
import helmet from 'helmet'
import type { Request, Response, NextFunction } from 'express'
export const securityMiddleware = (req: Request, res: Response, next: NextFunction) => {
const isProduction = process.env.NODE_ENV === 'production'
const isDevelopment = process.env.NODE_ENV === 'development'
if (isProduction) {
// Strict security for production
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "https:"],
scriptSrc: ["'self'"],
connectSrc: ["'self'"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
})(req, res, next)
} else if (isDevelopment) {
// More permissive for development
helmet({
contentSecurityPolicy: false, // Disable CSP in development for easier debugging
hsts: false // Disable HSTS in development
})(req, res, next)
} else {
next()
}
}
// Usage in server/index.ts
app.use(securityMiddleware)4. Custom Security Headers
// server/lib/security.ts
export const customSecurityHeaders = (req: Request, res: Response, next: NextFunction) => {
// Remove server information
res.removeHeader('X-Powered-By')
// Add custom security headers
res.setHeader('X-Content-Type-Options', 'nosniff')
res.setHeader('X-Frame-Options', 'DENY')
res.setHeader('X-XSS-Protection', '1; mode=block')
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin')
// Add security headers for API responses
if (req.path.startsWith('/api')) {
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate')
res.setHeader('Pragma', 'no-cache')
res.setHeader('Expires', '0')
}
next()
}5. Content Security Policy (CSP) Configuration
// server/lib/csp.ts
export const cspConfig = {
development: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "https:", "blob:"],
scriptSrc: ["'self'", "'unsafe-eval'", "'unsafe-inline'"], // Allow eval in development
connectSrc: ["'self'", "ws:", "wss:"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
},
},
production: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "https:"],
scriptSrc: ["'self'"],
connectSrc: ["'self'"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
blockAllMixedContent: true,
},
}
}Testing the Implementation
1. Security Header Tests
// tests/security-headers.test.ts
import request from 'supertest'
import app from '../server/index'
describe('Security Headers', () => {
it('should include essential security headers', async () => {
const response = await request(app)
.get('/')
.expect(200)
expect(response.headers['x-content-type-options']).toBe('nosniff')
expect(response.headers['x-frame-options']).toBe('DENY')
expect(response.headers['x-xss-protection']).toBe('1; mode=block')
expect(response.headers['referrer-policy']).toBe('strict-origin-when-cross-origin')
})
it('should include Content Security Policy header', async () => {
const response = await request(app)
.get('/')
.expect(200)
expect(response.headers['content-security-policy']).toBeDefined()
})
it('should include HSTS header in production', async () => {
process.env.NODE_ENV = 'production'
const response = await request(app)
.get('/')
.expect(200)
expect(response.headers['strict-transport-security']).toBeDefined()
})
})2. Security Testing Tools
# Install security testing tools
pnpm add -D @types/supertest supertest
# Test with security scanning tools
npx helmet-test http://localhost:3000
npx security-headers https://nsx.malloc.tokyo3. Manual Testing Checklist
- Test CSP with browser dev tools
- Verify X-Frame-Options prevents iframe embedding
- Check HSTS header in production
- Test XSS protection with malicious scripts
- Verify MIME sniffing protection
Monitoring and Alerting
1. Security Header Monitoring
// server/lib/security-monitor.ts
export const securityHeaderMonitor = (req: Request, res: Response, next: NextFunction) => {
const requiredHeaders = [
'x-content-type-options',
'x-frame-options',
'x-xss-protection',
'content-security-policy'
]
const missingHeaders = requiredHeaders.filter(header => !res.getHeader(header))
if (missingHeaders.length > 0) {
Logger.warn(`Missing security headers: ${missingHeaders.join(', ')}`)
}
next()
}2. CSP Violation Reporting
// Add CSP reporting endpoint
app.post('/api/csp-violation', (req: Request, res: Response) => {
Logger.warn('CSP Violation:', req.body)
res.status(204).send()
})Migration Strategy
Phase 1: Basic Security Headers
- Install helmet.js
- Add basic security headers
- Test in development
Phase 2: CSP Implementation
- Configure Content Security Policy
- Test with real application
- Fix any CSP violations
Phase 3: Production Hardening
- Enable HSTS
- Configure strict CSP
- Monitor for violations
Phase 4: Monitoring
- Add security header monitoring
- Set up CSP violation reporting
- Create alerting for security issues
Common Issues and Solutions
1. CSP Violations with External Resources
// Add specific domains to CSP
imgSrc: ["'self'", "data:", "https:", "https://example.com"]2. Inline Scripts and Styles
// Use nonces for inline scripts
scriptSrc: ["'self'", "'nonce-{random-nonce}'"]3. Development vs Production Differences
// Use environment-specific configurations
const cspConfig = process.env.NODE_ENV === 'production'
? productionCSP
: developmentCSPReferences
Priority: 🟠 High
Estimated Effort: 4-6 hours
Risk if not fixed: High - Multiple attack vectors
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels