TL;DR
WebSockets do not have the same security controls as HTTP. Cookies are sent on connection but not after, CORS does not apply, and CSRF tokens are not automatically included. Validate the Origin header, authenticate each message, and apply input validation to all WebSocket data.
WebSocket Security Challenges
- No CORS: Any website can open a WebSocket to your server
- Auth at connect time: Only the handshake includes cookies
- No CSRF protection: Browsers do not apply same-site restrictions
- Persistent connection: Session changes may not be reflected
Common Vulnerabilities
Cross-Site WebSocket Hijacking
Vulnerable: no origin check
// Server accepts connection without checking origin
wss.on('connection', (ws, req) => {
// req.headers.origin could be any site!
// If user is logged in, attacker site can connect
// and access their data via WebSocket
});
Secure WebSocket Setup
Proper origin and auth validation
const allowedOrigins = ['https://yoursite.com'];
wss.on('connection', (ws, req) => {
// Validate origin
const origin = req.headers.origin;
if (!allowedOrigins.includes(origin)) {
ws.close(1008, 'Origin not allowed');
return;
}
// Authenticate (example: token in query string)
const url = new URL(req.url, 'wss://yoursite.com');
const token = url.searchParams.get('token');
const user = validateToken(token);
if (!user) {
ws.close(1008, 'Unauthorized');
return;
}
// Store user for this connection
ws.user = user;
ws.on('message', (data) => {
// Validate and sanitize all incoming messages
const message = JSON.parse(data);
// Apply authorization for each action
});
});
Should I use wss:// or ws://?
Always use wss:// (WebSocket Secure) in production. Like HTTPS, it encrypts the connection and prevents interception.
How do I handle session expiry?
WebSocket connections persist after session expires. Implement periodic re-authentication or push session invalidation through the WebSocket itself.
Audit Your WebSockets
Our scanner checks WebSocket endpoints for common security issues.
Start Free Scan