Xay Dung He Thong Dong Thoi Real-time An Toan: Boi Ket WebSocket, OAuth 2.0 va JWT
Trong moi truong phat trien phan mem hien dai, viec lap dua lien ket hai chieu (two-way communication) giua khach hang va phat hanh khong con la yeu cau xa xoi ma da thanh tieu chuan cho nhung ung dung nhu chat, giao dich toan bo, hoac banh do thoi gian thuc. Tuy nhien, nhieu sysadmin va ky su phat trien thuong gap phai bat cong khi phoi hop cac giao thuc khac nhau. OAuth 2.0 duoc thi ke cho moi truong request-response nhu REST API, trong khi WebSocket duoc thi ke de du giu lien ket man len trong thoi gian dai. Viec ket noi hai he thuc nay ma khong co ky thuat dung dang se dan den loi an toan nghiêm trong hoac boi tri kha dung.
Bai viet nay se phan tich chi tiet cach xay dung mo hinh an toan de phep khach dung duoc thong ke qua WebSocket sau khi da dong nhap thanh cong qua OAuth 2.0. Thay vi bo tri OAuth trong tung tin nhat WebSocket (dieu se lam tang chi phu xac thuc va giam hieu suat), chung ta se dung JWT (JSON Web Token) de truyen thong tin nhan thue qua WebSocket, trong khi se duoc phep truy cap thuoc qua API OAuth. Day la mot chi phuc thuc te, duoc mo ta bang code cu the trong phan sau.
Phan Tich Xu Huong: TAI Sao Khong Nen Dung OAuth 2.0 Truc Tiep Tren WebSocket
OAuth 2.0 la mot giao thuc phep cap (authorization framework) thuong duoc dung de giao dich token truy cap (access token). Trong mo hinh REST, tung mot yeu cau HTTP se kham ket theo mot access token trong header Authorization. Tuy nhien, WebSocket la mot giao thuc duy nhat, co mot lien ket TCP duy nhat va du giu man. Nhoi dung du lieu duoc giao dien theo cac bao tin (frames) nhieu lan tren lien ket do.
Nhu vay, neu ta muon ung dung OAuth 2.0 theo cach thuan hieu, chung ta se phai gui mot tin nhat OAuth moi cho tung tin nhat WebSocket. Vi du, moi khi nguoi dung gui mot tin chat, server phai xac thuc lai toan bo token OAuth. Dieu nay se tao ra mot luong lon giao dich xac thuc khong can thiet, lam tang phuc tap cho server va giam kha nang mang. Hieu qua, chung ta se phan tich mo hinh duoc duoc duoc: khach dung dong nhap qua REST API OAuth de lay JWT, sau do JWT nay se duoc dung de xac thuc lien ket WebSocket thoi gian thuc.
Quy Trinh Lap Dua Lien Ket An Toan: Tu Dong Nhap Den WebSocket
De hieu ro quy trinh, chung ta se phan tich 3 giai doan chinh: Dong nhap, Lap lien ket WebSocket, va Xac thuc lien ket. Trong giai doan dong nhap, nguoi dung se gui ten dung va mat khau cho server. Server se kiem tra xac thuc va neu thanh cong, se tao ra mot JWT. JWT nay se chua thong tin can thieu nhu ID nguoi dung, vai tro, va thoi han hieu luc.
Sau khi co JWT, khach dung se bat dau lap lien ket WebSocket. Trong phan header cua lien ket WebSocket, ho se gui thong tin xac thuc. Mot cach thong minh la dung header Authorization co gia tri la "Bearer ". Server WebSocket se can canh thieu can thuc moi lien ket nhap vao, lay token tu header, va kiem tra tinh hang chat cua JWT. Neu JWT hop le va chua han, lien ket se duoc cap phep va di vao tinh trang "open". Sau do, tung tin nhat WebSocket se duoc xac thuc nhanh khong can gui lai token.
Trien Khai Phan Dong: Server Xac Thuc WebSocket voi Node.js va JWT
De minh hoa chi tieu, chung ta se su dung Node.js voi thung bao socket.io (mot thung bao WebSocket pho bien) va thung bao jsonwebtoken (jwt) de xac thuc. Trong phan nay, toi se viet mot code minh hoa cho server. Code nay se thuc hien viec dong nhap qua OAuth 2.0 (gioi han trong phan nay la mot API moi giup tao JWT) va sau do thuc hien viec xac thuc lien ket WebSocket.
Dau tien, chung ta can khai bao cac thung can thieu. Trong file package.json, chung ta se co cac thung nhu express, socket.io, va jsonwebtoken. Sau do, chung ta se viet code cho server. Trong phan code, chung ta se co mot API REST de dong nhap. Khi nguoi dung gui yeu cau dong nhap, server se kiem tra ten dung va mat khau. Neu dung, server se tao JWT va phan hoi ve cho khach dung.
const express = require('express');
const jwt = require('jsonwebtoken');
const http = require('http');
const { Server } = require("socket.io");
const cors = require('cors');
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "https://example.com",
methods: ["GET", "POST"]
}
});
app.use(express.json());
// Bien giau cho mat khau va secret key (trong thuc te phai la moi truong)
const SECRET_KEY = "my_super_secret_key_do_not_share";
const users = {
"admin": { id: 1, password: "admin123", role: "admin" },
"user": { id: 2, password: "user123", role: "user" }
};
// API OAuth: Dong nhap va tao JWT
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
const user = users[username];
if (!user || user.password !== password) {
return res.status(401).json({ error: "Ten dung hoac mat khau sai" });
}
const token = jwt.sign(
{ id: user.id, username: user.username, role: user.role },
SECRET_KEY,
{ expiresIn: '1h' }
);
res.json({ token: token, user: { id: user.id, username: user.username } });
});
// Xac thuc WebSocket: Middleware de kiem tra JWT
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error("That thieu token xac thuc"));
}
try {
const decoded = jwt.verify(token, SECRET_KEY);
socket.user = decoded; // Luu thong tin nguoi dung vao socket
next();
} catch (err) {
next(new Error("Token khong hop le"));
}
});
// Su kien ket noi thanh cong
io.on('connection', (socket) => {
console.log(`Nguoi dung ${socket.user.username} da ket noi vao, ID: ${socket.user.id}`);
// Gui tin nhat den server
socket.on('chat_message', (data) => {
// Server co the kiem tra role nguoi dung neu can
console.log(`Tin nhat tu ${socket.user.username}: ${data.message}`);
io.emit('chat_message', {
user: socket.user.username,
message: data.message,
role: socket.user.role
});
});
// Nguoi dung that lien ket
socket.on('disconnect', () => {
console.log(`Nguoi dung ${socket.user.username} da mat lien ket`);
});
});
server.listen(3000, () => {
console.log('Server dong tai port 3000');
});
Trong code tren, chung ta thay ro viec thuc hien. API /api/login se xac thuc ten dung va mat khau, sau do tao JWT. JWT duoc kenh qua header Authorization trong yeu cau HTTP. Khi nguoi dung muon ket noi WebSocket, ho phai gui token trong phan auth cua handshake. Server se dung jwt.verify de kiem tra token. Neu thanh cong, thong tin nguoi dung se duoc luu vao doi tuong socket.user. Day la mot cach thuc hien an toan va hieu qua.
Trien Khai Phan Dong: Khach Dung Ket Noi voi Token
Ti do, chung ta xem xet phan dong, tinh la nguoi dung. Trong mo hinh nay, khach dung phai thuc hien hai buoc. Buoc dau la goi API /api/login de lay token. Buoc hai la su dung token do de ket noi WebSocket. Trong phan code minh hoa, chung ta se su dung thung socket.io client va fetch API de thuc hien viec nay.
Vi du, chung ta co mot file HTML nho co thuc hien viec dong nhap va ket noi. Sau khi nguoi dung nhap ten dung va mat khau, javascript se goi API login. Neu thanh cong, se lay token va su dung token do de ket noi WebSocket. Trong phan ket noi, chung ta se gui token trong phan auth cua handshake. Sau khi ket noi thanh cong, nguoi dung co the gui tin chat.
// File: client.js
const socket = io('https://example.com', {
auth: {
token: localStorage.getItem('authToken') // Lay token da luu
}
});
// Ham dong nhap
function login(username, password) {
fetch('https://example.com/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
})
.then(res => res.json())
.then(data => {
if (data.token) {
localStorage.setItem('authToken', data.token);
console.log("Dong nhap thanh cong!");
socket.connect();
} else {
console.error("Dong nhap that bai:", data.error);
}
})
.catch(err => console.error("Loi:", err));
}
// Su kien ket noi thanh cong
socket.on('connect', () => {
console.log("Ket noi WebSocket thanh cong!");
});
// Su kien that bai ket noi
socket.on('connect_error', (err) => {
console.error("That bai ket noi:", err.message);
// Co the xu ly: xoa token va yeu cau dong nhap lai
localStorage.removeItem('authToken');
});
// Su kien nhan tin nhat tu server
socket.on('chat_message', (data) => {
console.log(`Nhan tin: ${data.user} - ${data.message}`);
// Cap nhat giao dien o day
});
// Ham gui tin nhat
function sendMessage(message) {
socket.emit('chat_message', { message: message });
}
Trong code client, chung ta thay ro viec quan ly token. Sau khi dong nhap thanh cong, token se duoc luu vao localStorage. Khi khach dung muon ket noi WebSocket, ho se lay token tu localStorage va gui trong phan auth cua handshake. Neu server that bai xac thuc (vi du token qua han), socket se trigger su kien connect_error. Trong su kien nay, chung ta co the xoa token va yeu cau nguoi dung dong nhap lai. Day la mot quy trinh co ban nhưng quan trong de dam bao an toan.
Xu Ly Thoi Han Token va Canh Nhat Token
Mot van de thuong gap khi dung JWT la thoi han hieu luc. JWT thuong co thoi han ngan (vai phut hoac mot gi) de giam thue an toan neu token bi da. Khi token qua han, lien ket WebSocket se that bai khi thu thuc hien xac thuc. Trong mo hinh REST, chung ta co the dung Refresh Token de lan can tao Access Token moi ma khong can dong nhap lai. Tuy nhien, trong WebSocket, viec nay phu tac hon.
Mot cach xu ly la de server boi tri thoi han hieu luc cua JWT duoc dai hon (vdi) trong mo hinh real-time, nhung day la mot risk an toan. Cach tot hon la cho phep lien ket WebSocket duoc giu man cho den khi token qua han, va khi do se boi tri token moi. De lam duoc viec nay, chung ta co the thuc hien mot su kien "refresh_token" trong WebSocket. Khi token qua han, server se boi tri lien ket, va khach dung se phai gui yu cau refresh token. Server se kiem tra refresh token (duoc luu o server hoac trong cookie an toan) va tao access token moi. Sau do, khach dung se phai lap lai lien ket WebSocket voi token moi.
Hoac, mot cach thuc hien khac la dung Refresh Token trong session HTTP, va khi token Access qua han, server se boi tri lien ket WebSocket, va yeu cau khach dung goi API /api/refresh-token de lay access token moi, sau do lap lai lien ket. Trong mo hinh nay, chung ta co the thuc hien mot ham auto-refresh trong client. Khi nhan thuong tinh toan, client se goi API refresh va ket noi lai neu can thiet.
// Example: Client auto-reconnect when token expires
socket.on('disconnect', (reason) => {
if (reason === 'io server disconnect') {
// Server boi tri lien ket, co the la do token qua han
console.log("Lien ket that bai, thu ket noi lai voi token moi");
refreshAndReconnect();
}
});
async function refreshAndReconnect() {
try {
const res = await fetch('https://example.com/api/refresh-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('refreshToken')}`
}
});
const data = await res.json();
if (data.token) {
localStorage.setItem('authToken', data.token);
socket.auth.token = data.token;
socket.connect();
}
} catch (err) {
console.error("That bai refresh token, yeu cau dong nhap lai");
}
}
Cac Dich Thuyet An Toan Khac Can Thuc Hien
Ben canh vi xac thuc qua JWT, con co mot so dich thuyet an toan khac can thuc hien khi xay dung he thong WebSocket. Dau tien la chong cong vao DoS (Denial of Service). WebSocket co the duoc dung de tao ra nhieu lien ket dong thoi, lam ton tai server. Vi vay, chung ta can bat giu so lien ket cho moi IP hoac moi nguoi dung. Trong socket.io, chung ta co the thuc hien viec nay bang cach kiem tra so lien ket trong middleware.
Ti do, chung ta can boi tri lien ket tu do. Khach dung co the gui nhieu tin nhat trong thoi gian ngan, lam qua tay server. Vi vay, chung ta can thuc hien rate limiting cho tung lien ket WebSocket. Trong socket.io, chung ta co the su dung thung bao rate-limiter de boi tri lien ket neu nguoi dung gui qua nhieu tin nhat trong thoi gian ngan.
Boi tri lien ket tu do cung quan trong. Khach dung co the gui lien ket tu do (malicious payloads) vao server. Vi vay, chung ta can kiem tra va sang su du lieu truoc khi xuly. Trong phan code server, chung ta co the kiem tra kich thuoc tin nhat, hay kiem tra kiem thuat gui. Vi du, neu tin nhat chat co kich thuoc hon 1024 ky tu, chung ta se boi tri lien ket.
Cuoi cung, chung ta can bao mat lien ket. WebSocket nen duoc trian khai qua WSS (WebSocket Secure), tuong duong voi HTTPS. Dieu nay se bao mat du lieu trong qua trinh giao dien, chong ngan nghe (eavesdropping). Trong socket.io, chung ta co the boi tri lien ket WSS bang cach boi tri lien ket tu do, va yeu cau lien ket qua WSS. Trong phan code server, chung ta co the thuc hien viec nay bang cach kiem tra protocol cua lien ket.
// Example: Check protocol and limit connection size
io.use((socket, next) => {
if (socket.request.headers && socket.request.headers['x-forwarded-proto'] !== 'https') {
return next(new Error("Yeu cau lien ket qua HTTPS/WSS"));
}
next();
});
// Limit message size
io.on('connection', (socket) => {
socket.on('message', (data) => {
if (typeof data === 'string' && data.length > 1024) {
socket.disconnect(true); // Boi tri lien ket
return;
}
// Xu ly tin nhat...
});
});
Ket Luan
Xay dung he thong dong thoi real-time an toan la mot thach thuc ky thuat, yeu cau hieu ro ve OAuth 2.0, JWT, va WebSocket. Bang cach boi ket OAuth 2.0 de dong nhap va JWT de xac thuc lien ket WebSocket, chung ta co thuc hien duoc mot he thong an toan va hieu qua. Quy trinh nay bao gom dong nhap qua REST API, tao JWT, va xac thuc lien ket WebSocket qua JWT. Ben canh vi xac thuc, chung ta can thuc hien cac dich thuyet an toan khac nhu chong DoS, rate limiting, va bao mat lien ket. Vi du minh hoa bang Node.js va socket.io tren day cung cap mot co so de cho cac ky su phat trien trian khai he thong cua minh.