blog.dopana

Back

Xác thực (authentication) và phân quyền (authorization) là hai việc khác nhau. Auth xác định bạn là ai, authorization xác định bạn được làm gì.

Authentication — Bạn Là Ai?#

JWT — JSON Web Token#

JWT gồm 3 phần: header.payload.signature:

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.abc123...
plaintext

JWT Best Practices#

  • Access token ngắn (15 phút) — giảm thiểu rủi ro nếu bị lộ
  • Refresh token dài (7-30 ngày) — lưu trong httpOnly cookie
  • Không lưu secret trong code — dùng env variable
  • Secret mạnh — ít nhất 256-bit random
  • Có rotation — đổi refresh token mỗi lần dùng

Refresh Token Flow#

OAuth2 — Ủy Quyền Cho Bên Thứ Ba#

OAuth2 cho phép user đăng nhập bằng Google, GitHub, Facebook mà không cần share password.

Flow Authorization Code#

User → App → Redirect → Google Login → Authorization Code → App Server

                                            App Server → Google → Access Token

                                            App Server dùng token gọi Google API
plaintext

Authorization — Bạn Được Làm Gì?#

RBAC — Role-Based Access Control#

ABAC — Attribute-Based Access Control#

function canAccessResource(user: User, resource: Resource): boolean {
  // Admin access everything
  if (user.role === 'admin') return true;

  // User chỉ access resource của mình
  if (resource.ownerId === user.id) return true;

  // Moderator xoá bài vi phạm
  if (user.role === 'moderator' && resource.type === 'post' && resource.flagged) {
    return true;
  }

  return false;
}
typescript

Bảo Vệ Endpoint#

Rate Limiting#

import rateLimit from 'express-rate-limit';

// Global — 100 request/phút
app.use(rateLimit({
  windowMs: 60 * 1000,
  max: 100,
}));

// Auth endpoints — strict hơn
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: 'Too many login attempts',
});
app.use('/auth/login', authLimiter);
typescript

Input Validation#

CSRF Protection#

import csrf from 'csurf';

app.use(csrf({ cookie: true }));

// Gửi CSRF token trong form
app.get('/form', (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});
typescript

Security Headers#

Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'self'
Referrer-Policy: strict-origin-when-cross-origin
bash

Password — Không Bao Giờ Lưu Plain Text#

Logout & Revoke#

Checklist#

  • JWT với access token ngắn hạn + refresh token rotation
  • Password hash bằng bcrypt (cost ≥ 12)
  • Rate limiting trên auth endpoints
  • Input validation (Zod, Joi)
  • CSRF protection cho cookie-based auth
  • Security headers (helmet)
  • HTTPS mandatory
  • CORS whitelist
  • Audit log cho hành động nhạy cảm
  • Dependency scan (npm audit)

Kết Luận#

Security là layered defense. JWT cho stateless auth, refresh token cho UX, OAuth2 cho third-party login, RBAC/ABAC cho authorization. Không có “đủ an toàn” — chỉ có “đủ an toàn cho hôm nay”.

Tài liệu tham khảo#