CORS for WebSockets — Cross-Origin WebSocket Connections and Security
In this tutorial, you will learn about CORS for WebSockets. We cover key concepts, practical examples, and best practices to help you master this topic.
Websocket connections have a different CORS model than HTTP: the browser sends the Origin header during the handshake, but the server must validate it since the browser does not enforce CORS on WebSocket data frames.
What You'll Learn
- How CORS works (and differs) for WebSockets
- Server-side origin validation for WebSocket handshakes
- Security considerations for cross-origin WebSocket connections
Why It Matters
Real-time applications using WebSockets need cross-origin support. Unlike HTTP CORS, WebSocket CORS relies entirely on server-side validation. DodaTech's real-time threat dashboard uses WebSockets with strict origin validation.
sequenceDiagram
Browser->>Server: HTTP Upgrade Request
Browser->>Server: Origin: https://app.example.com
Server-->>Browser: 101 Switching Protocols
Note over Server: Server MUST validate Origin
Browser->>Server: WebSocket data frames
Note over Server: Browser does not check CORS for frames
Code Examples
// Browser WebSocket with CORS
const ws = new WebSocket('wss://realtime.example.com/events');
// The browser sends the Origin header automatically
// during the HTTP upgrade handshake
ws.onopen = () => {
console.log('WebSocket connected');
ws.send(JSON.stringify({type: 'subscribe', channel: 'alerts'}));
};
ws.onmessage = (event) => {
console.log('Received:', event.data);
};
# Server-side WebSocket origin validation in Python
import asyncio
import websockets
ALLOWED_ORIGINS = [
'https://app.example.com',
'https://admin.example.com',
]
async def handler(websocket):
# Validate origin during handshake
origin = websocket.request_headers.get('Origin', '')
if origin not in ALLOWED_ORIGINS:
await websocket.close(
4001, 'Origin not allowed'
)
return
print(f'WebSocket connection from allowed origin: {origin}')
async for message in websocket:
# Process message
pass
async def main():
async with websockets.serve(
handler, '0.0.0.0', 8765
):
await asyncio.Future()
// Node.js WebSocket server with origin validation
const WebSocket = require('ws');
const ALLOWED_ORIGINS = [
'https://app.example.com',
'https://admin.example.com'
];
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws, req) => {
const origin = req.headers.origin;
if (!origin || !ALLOWED_ORIGINS.includes(origin)) {
console.log(`Rejected connection from origin: ${origin}`);
ws.close(4001, 'Origin not allowed');
return;
}
console.log(`Accepted connection from: ${origin}`);
ws.on('message', (data) => {
ws.send(`Echo: ${data}`);
});
});
# Test WebSocket origin validation
python3 -c "
import websockets
import asyncio
async def test():
async with websockets.connect(
'wss://realtime.example.com/events',
origin='https://evil.com'
) as ws:
print('Connected with evil origin')
await ws.close()
try:
asyncio.run(test())
except Exception as e:
print(f'Connection rejected: {e}')
"
Common Mistakes
1. Relying on Browser CORS Enforcement for WebSockets
Browsers do not enforce CORS on WebSocket message frames. Server-side validation is essential.
2. Not Validating Origin During WebSocket Handshake
Without origin validation, any website can connect to your WebSocket server.
3. Using HTTP CORS Headers for WebSockets
WebSocket CORS is handled during the handshake, not via Access-Control-* headers.
4. Allowing All Origins in Development and Forgetting to Restrict
Production WebSocket servers must have strict origin validation.
5. Not Handling the Upgrade Request Correctly
The WebSocket upgrade request requires specific handling for CORS headers.
Practice Questions
- Does the browser enforce CORS on WebSocket data frames?
- How does the server validate WebSocket origins?
- What header does the browser send during the WebSocket handshake?
- Can WebSocket CORS use Access-Control-Allow-Origin?
- How do you close a WebSocket connection due to invalid origin?
Answers:
- No. The browser only sends the Origin header. CORS enforcement is entirely server-side.
- By checking the Origin header in the HTTP upgrade request against a whitelist.
- The Origin header, same as HTTP CORS.
- No. WebSocket CORS uses the Origin header during the handshake, not HTTP CORS headers.
- Call websocket.close(4001, 'Origin not allowed').
Challenge: Build a real-time chat application with WebSockets. Implement origin validation, multiple allowed origins, and a fallback mechanism for connections without an Origin header.
FAQ
Mini Project
Build a real-time event streaming service with WebSocket support for multiple frontend applications. Implement origin validation per channel (public channels allow any origin, private channels require specific origins), add connection logging, and create a WebSocket CORS testing tool.
What's Next
Complete the CORS project to apply all CORS concepts, or explore the CORS series summary for a comprehensive review.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro