Refactor auth-service to iam-service and update related documentation
- Renamed auth-service to iam-service across various files for consistency. - Updated Dockerfiles, deployment configurations, and documentation to reflect the service name change. - Enhanced testing commands in documentation to point to the new iam-service. - Removed outdated auth-service files and configurations to streamline the project structure. - Improved bilingual documentation for clarity on the new service structure and usage.
This commit is contained in:
742
docs/en/skills/security.md
Normal file
742
docs/en/skills/security.md
Normal file
@@ -0,0 +1,742 @@
|
||||
# Security / Bảo Mật
|
||||
|
||||
> **EN**: Security best practices and patterns for GoodGo microservices platform. Use when implementing authentication, authorization, data protection, input validation, rate limiting, secrets management, or security testing across all services.
|
||||
> **VI**: Thực hành và mẫu bảo mật tốt nhất cho nền tảng microservices GoodGo. Sử dụng khi triển khai xác thực, phân quyền, bảo vệ dữ liệu, xác thực đầu vào, giới hạn tốc độ, quản lý bí mật hoặc kiểm tra bảo mật trên tất cả các dịch vụ.
|
||||
|
||||
## Overview / Tổng Quan
|
||||
|
||||
**EN**: The Security skill provides comprehensive security patterns, best practices, and implementation examples for protecting GoodGo microservices. It covers authentication, authorization, data protection, input validation, rate limiting, secrets management, and security testing.
|
||||
|
||||
**VI**: Skill Security cung cấp các mẫu bảo mật toàn diện, thực hành tốt nhất và ví dụ triển khai để bảo vệ các microservices GoodGo. Nó bao gồm xác thực, phân quyền, bảo vệ dữ liệu, xác thực đầu vào, giới hạn tốc độ, quản lý bí mật và kiểm tra bảo mật.
|
||||
|
||||
## When to Use / Khi Nào Sử Dụng
|
||||
|
||||
**EN**: Use this skill when:
|
||||
- Implementing authentication and authorization in any service
|
||||
- Protecting sensitive data (PII, credentials, tokens)
|
||||
- Validating user inputs and file uploads
|
||||
- Implementing rate limiting and DDoS protection
|
||||
- Setting up audit logging and security monitoring
|
||||
- Encrypting data at rest and in transit
|
||||
- Managing secrets and credentials
|
||||
- Implementing security testing
|
||||
- Handling security incidents
|
||||
- Designing secure API endpoints
|
||||
|
||||
**VI**: Sử dụng skill này khi:
|
||||
- Triển khai xác thực và phân quyền trong bất kỳ service nào
|
||||
- Bảo vệ dữ liệu nhạy cảm (PII, thông tin đăng nhập, token)
|
||||
- Xác thực đầu vào người dùng và tải lên tệp
|
||||
- Triển khai giới hạn tốc độ và bảo vệ DDoS
|
||||
- Thiết lập ghi nhật ký kiểm toán và giám sát bảo mật
|
||||
- Mã hóa dữ liệu khi nghỉ và khi truyền
|
||||
- Quản lý bí mật và thông tin đăng nhập
|
||||
- Triển khai kiểm tra bảo mật
|
||||
- Xử lý sự cố bảo mật
|
||||
- Thiết kế các endpoint API an toàn
|
||||
|
||||
## Key Concepts / Khái Niệm Chính
|
||||
|
||||
### Core Security Principles / Nguyên Tắc Bảo Mật Cốt Lõi
|
||||
|
||||
**EN**:
|
||||
1. **Defense in Depth**: Multiple layers of security controls
|
||||
2. **Least Privilege**: Grant minimum required permissions
|
||||
3. **Fail Secure**: Default to deny access
|
||||
4. **Separation of Duties**: Critical operations require multiple approvals
|
||||
5. **Audit Everything**: Log all security-relevant events
|
||||
6. **Encrypt Sensitive Data**: PII, tokens, credentials must be encrypted
|
||||
7. **Validate All Inputs**: Never trust user input
|
||||
8. **Principle of Least Exposure**: Minimize attack surface
|
||||
9. **Secure by Default**: Security built-in, not bolted on
|
||||
10. **Assume Breach**: Design for detection and response
|
||||
|
||||
**VI**:
|
||||
1. **Defense in Depth**: Nhiều lớp kiểm soát bảo mật
|
||||
2. **Least Privilege**: Cấp quyền tối thiểu cần thiết
|
||||
3. **Fail Secure**: Mặc định từ chối truy cập
|
||||
4. **Separation of Duties**: Các thao tác quan trọng yêu cầu nhiều phê duyệt
|
||||
5. **Audit Everything**: Ghi log tất cả sự kiện liên quan đến bảo mật
|
||||
6. **Encrypt Sensitive Data**: PII, token, thông tin đăng nhập phải được mã hóa
|
||||
7. **Validate All Inputs**: Không bao giờ tin tưởng đầu vào người dùng
|
||||
8. **Principle of Least Exposure**: Giảm thiểu bề mặt tấn công
|
||||
9. **Secure by Default**: Bảo mật được tích hợp sẵn, không phải thêm vào sau
|
||||
10. **Assume Breach**: Thiết kế để phát hiện và phản ứng
|
||||
|
||||
## Common Patterns / Các Pattern Thường Dùng
|
||||
|
||||
### Authentication & Authorization / Xác Thực & Phân Quyền
|
||||
|
||||
#### JWT Token Validation / Xác Thực Token JWT
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/auth.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { jwtService } from '../modules/token/jwt.service';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
export const authenticate = () => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Extract token from Authorization header or cookie
|
||||
let token: string | null = null;
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
if (authHeader?.startsWith('Bearer ')) {
|
||||
token = authHeader.substring(7);
|
||||
} else if (req.cookies?.access_token) {
|
||||
token = req.cookies.access_token;
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_001', message: 'Authentication required' }
|
||||
});
|
||||
}
|
||||
|
||||
// Verify token
|
||||
const payload = await jwtService.verifyAccessToken(token);
|
||||
|
||||
// Attach user to request
|
||||
req.user = {
|
||||
id: payload.sub,
|
||||
userId: payload.sub,
|
||||
email: payload.email,
|
||||
roles: payload.roles || [],
|
||||
permissions: payload.permissions || []
|
||||
};
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.warn('Authentication failed', { error: error.message });
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_002', message: 'Invalid or expired token' }
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/auth.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { jwtService } from '../modules/token/jwt.service';
|
||||
import { logger } from '@goodgo/logger';
|
||||
|
||||
export const authenticate = () => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Trích xuất token từ header Authorization hoặc cookie
|
||||
let token: string | null = null;
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
if (authHeader?.startsWith('Bearer ')) {
|
||||
token = authHeader.substring(7);
|
||||
} else if (req.cookies?.access_token) {
|
||||
token = req.cookies.access_token;
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_001', message: 'Yêu cầu xác thực' }
|
||||
});
|
||||
}
|
||||
|
||||
// Xác minh token
|
||||
const payload = await jwtService.verifyAccessToken(token);
|
||||
|
||||
// Gắn user vào request
|
||||
req.user = {
|
||||
id: payload.sub,
|
||||
userId: payload.sub,
|
||||
email: payload.email,
|
||||
roles: payload.roles || [],
|
||||
permissions: payload.permissions || []
|
||||
};
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.warn('Xác thực thất bại', { error: error.message });
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'AUTH_002', message: 'Token không hợp lệ hoặc hết hạn' }
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
#### Permission-Based Authorization / Phân Quyền Dựa Trên Quyền
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/rbac.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
export const requirePermission = (
|
||||
resource: string,
|
||||
action: string,
|
||||
scope?: string
|
||||
) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'UNAUTHORIZED', message: 'Authentication required' }
|
||||
});
|
||||
}
|
||||
|
||||
const hasPermission = await rbacService.hasPermission(
|
||||
userId,
|
||||
resource,
|
||||
action,
|
||||
scope
|
||||
);
|
||||
|
||||
if (!hasPermission) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INSUFFICIENT_PERMISSIONS',
|
||||
message: `Requires ${action} permission on ${resource}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/rbac.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
export const requirePermission = (
|
||||
resource: string,
|
||||
action: string,
|
||||
scope?: string
|
||||
) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: { code: 'UNAUTHORIZED', message: 'Yêu cầu xác thực' }
|
||||
});
|
||||
}
|
||||
|
||||
const hasPermission = await rbacService.hasPermission(
|
||||
userId,
|
||||
resource,
|
||||
action,
|
||||
scope
|
||||
);
|
||||
|
||||
if (!hasPermission) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INSUFFICIENT_PERMISSIONS',
|
||||
message: `Yêu cầu quyền ${action} trên ${resource}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Input Validation / Xác Thực Đầu Vào
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/validation.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { AnyZodObject, ZodError } from 'zod';
|
||||
|
||||
export const validateDto = (
|
||||
schema: AnyZodObject,
|
||||
property: 'body' | 'query' | 'params' = 'body'
|
||||
) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Sanitize input by trimming strings
|
||||
const sanitizedData = sanitizeInput(req[property]);
|
||||
|
||||
// Validate the sanitized data
|
||||
const validatedData = schema.parse(sanitizedData);
|
||||
|
||||
// Replace original data with validated data
|
||||
(req as any)[property] = validatedData;
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Invalid request data',
|
||||
details: error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message,
|
||||
code: err.code
|
||||
}))
|
||||
}
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function sanitizeInput(data: any): any {
|
||||
if (typeof data === 'string') {
|
||||
return data.trim();
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(sanitizeInput);
|
||||
}
|
||||
if (data !== null && typeof data === 'object') {
|
||||
const sanitized: any = {};
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
sanitized[key] = sanitizeInput(value);
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/validation.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import { AnyZodObject, ZodError } from 'zod';
|
||||
|
||||
export const validateDto = (
|
||||
schema: AnyZodObject,
|
||||
property: 'body' | 'query' | 'params' = 'body'
|
||||
) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
// Làm sạch đầu vào bằng cách cắt chuỗi
|
||||
const sanitizedData = sanitizeInput(req[property]);
|
||||
|
||||
// Xác thực dữ liệu đã được làm sạch
|
||||
const validatedData = schema.parse(sanitizedData);
|
||||
|
||||
// Thay thế dữ liệu gốc bằng dữ liệu đã xác thực
|
||||
(req as any)[property] = validatedData;
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Dữ liệu request không hợp lệ',
|
||||
details: error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message,
|
||||
code: err.code
|
||||
}))
|
||||
}
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function sanitizeInput(data: any): any {
|
||||
if (typeof data === 'string') {
|
||||
return data.trim();
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(sanitizeInput);
|
||||
}
|
||||
if (data !== null && typeof data === 'object') {
|
||||
const sanitized: any = {};
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
sanitized[key] = sanitizeInput(value);
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting / Giới Hạn Tốc Độ
|
||||
|
||||
**EN**: Example from `services/iam-service/src/middlewares/rate-limit.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { RateLimiterRedis } from 'rate-limit-redis';
|
||||
import { getRedisClient } from '../config/redis.config';
|
||||
|
||||
export const dynamicRateLimit = async (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
// Default limits
|
||||
let windowMs = 15 * 60 * 1000; // 15 minutes
|
||||
let max = 100; // 100 requests
|
||||
|
||||
if (userId) {
|
||||
const roles = await rbacService.getUserRoles(userId);
|
||||
|
||||
// Set limits based on role
|
||||
if (roles.includes('SUPER_ADMIN')) {
|
||||
max = 1000;
|
||||
} else if (roles.includes('ADMIN')) {
|
||||
max = 500;
|
||||
} else if (roles.includes('MODERATOR')) {
|
||||
max = 300;
|
||||
}
|
||||
} else {
|
||||
// Unauthenticated users - stricter limits
|
||||
max = 50;
|
||||
}
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
store: new RateLimiterRedis({
|
||||
client: getRedisClient(),
|
||||
prefix: 'rl:'
|
||||
}),
|
||||
handler: (req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
limiter(req, res, next);
|
||||
};
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/middlewares/rate-limit.middleware.ts`:
|
||||
|
||||
```typescript
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { RateLimiterRedis } from 'rate-limit-redis';
|
||||
import { getRedisClient } from '../config/redis.config';
|
||||
|
||||
export const dynamicRateLimit = async (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => {
|
||||
const userId = req.user?.id || req.user?.sub;
|
||||
|
||||
// Giới hạn mặc định
|
||||
let windowMs = 15 * 60 * 1000; // 15 phút
|
||||
let max = 100; // 100 requests
|
||||
|
||||
if (userId) {
|
||||
const roles = await rbacService.getUserRoles(userId);
|
||||
|
||||
// Đặt giới hạn dựa trên vai trò
|
||||
if (roles.includes('SUPER_ADMIN')) {
|
||||
max = 1000;
|
||||
} else if (roles.includes('ADMIN')) {
|
||||
max = 500;
|
||||
} else if (roles.includes('MODERATOR')) {
|
||||
max = 300;
|
||||
}
|
||||
} else {
|
||||
// Người dùng chưa xác thực - giới hạn nghiêm ngặt hơn
|
||||
max = 50;
|
||||
}
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs,
|
||||
max,
|
||||
store: new RateLimiterRedis({
|
||||
client: getRedisClient(),
|
||||
prefix: 'rl:'
|
||||
}),
|
||||
handler: (req, res) => {
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Quá nhiều yêu cầu, vui lòng thử lại sau'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
limiter(req, res, next);
|
||||
};
|
||||
```
|
||||
|
||||
### Security Headers / Header Bảo Mật
|
||||
|
||||
**EN**: Example from `services/iam-service/src/main.ts`:
|
||||
|
||||
```typescript
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
|
||||
// Security middleware
|
||||
app.use(helmet());
|
||||
app.use(cors({
|
||||
origin: appConfig.corsOrigin,
|
||||
credentials: true
|
||||
}));
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/main.ts`:
|
||||
|
||||
```typescript
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
|
||||
// Middleware bảo mật
|
||||
app.use(helmet());
|
||||
app.use(cors({
|
||||
origin: appConfig.corsOrigin,
|
||||
credentials: true
|
||||
}));
|
||||
```
|
||||
|
||||
**EN**: Traefik security headers from `infra/traefik/dynamic/middlewares.yml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
middlewares:
|
||||
secure-headers:
|
||||
headers:
|
||||
sslRedirect: true
|
||||
stsSeconds: 31536000
|
||||
contentTypeNosniff: true
|
||||
browserXssFilter: true
|
||||
frameDeny: true
|
||||
customRequestHeaders:
|
||||
X-Forwarded-Proto: "https"
|
||||
```
|
||||
|
||||
**VI**: Header bảo mật Traefik từ `infra/traefik/dynamic/middlewares.yml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
middlewares:
|
||||
secure-headers:
|
||||
headers:
|
||||
sslRedirect: true
|
||||
stsSeconds: 31536000
|
||||
contentTypeNosniff: true
|
||||
browserXssFilter: true
|
||||
frameDeny: true
|
||||
customRequestHeaders:
|
||||
X-Forwarded-Proto: "https"
|
||||
```
|
||||
|
||||
### Audit Logging / Ghi Log Kiểm Toán
|
||||
|
||||
**EN**: Example from `services/iam-service/src/core/events/audit.service.ts`:
|
||||
|
||||
```typescript
|
||||
export class AuditService {
|
||||
async logAuthEvent(
|
||||
eventType: string,
|
||||
data: {
|
||||
userId?: string;
|
||||
success: boolean;
|
||||
errorMessage?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
metadata?: any;
|
||||
}
|
||||
): Promise<void> {
|
||||
await this.prisma.authEvent.create({
|
||||
data: {
|
||||
userId: data.userId || null,
|
||||
eventType,
|
||||
eventData: data.metadata || {},
|
||||
ipAddress: data.ipAddress,
|
||||
userAgent: data.userAgent,
|
||||
success: data.success,
|
||||
errorMessage: data.errorMessage
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**VI**: Ví dụ từ `services/iam-service/src/core/events/audit.service.ts`:
|
||||
|
||||
```typescript
|
||||
export class AuditService {
|
||||
async logAuthEvent(
|
||||
eventType: string,
|
||||
data: {
|
||||
userId?: string;
|
||||
success: boolean;
|
||||
errorMessage?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
metadata?: any;
|
||||
}
|
||||
): Promise<void> {
|
||||
await this.prisma.authEvent.create({
|
||||
data: {
|
||||
userId: data.userId || null,
|
||||
eventType,
|
||||
eventData: data.metadata || {},
|
||||
ipAddress: data.ipAddress,
|
||||
userAgent: data.userAgent,
|
||||
success: data.success,
|
||||
errorMessage: data.errorMessage
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices / Thực Hành Tốt Nhất
|
||||
|
||||
### Password Security / Bảo Mật Mật Khẩu
|
||||
|
||||
**EN**:
|
||||
- Always use bcrypt with cost factor 12+ in production
|
||||
- Never log passwords or password hashes
|
||||
- Use strong password requirements (min 8 chars, uppercase, lowercase, number, special char)
|
||||
- Implement password reset with secure tokens
|
||||
|
||||
**VI**:
|
||||
- Luôn sử dụng bcrypt với hệ số chi phí 12+ trong production
|
||||
- Không bao giờ ghi log mật khẩu hoặc hash mật khẩu
|
||||
- Sử dụng yêu cầu mật khẩu mạnh (tối thiểu 8 ký tự, chữ hoa, chữ thường, số, ký tự đặc biệt)
|
||||
- Triển khai đặt lại mật khẩu với token an toàn
|
||||
|
||||
### Token Security / Bảo Mật Token
|
||||
|
||||
**EN**:
|
||||
- Hash tokens before storing in database
|
||||
- Use short-lived access tokens (15 minutes)
|
||||
- Use longer-lived refresh tokens (7 days) with rotation
|
||||
- Store refresh tokens securely (httpOnly cookies)
|
||||
- Implement token revocation
|
||||
|
||||
**VI**:
|
||||
- Hash token trước khi lưu vào database
|
||||
- Sử dụng access token có thời gian sống ngắn (15 phút)
|
||||
- Sử dụng refresh token có thời gian sống dài hơn (7 ngày) với xoay vòng
|
||||
- Lưu trữ refresh token an toàn (httpOnly cookies)
|
||||
- Triển khai thu hồi token
|
||||
|
||||
### SQL Injection Prevention / Ngăn Chặn SQL Injection
|
||||
|
||||
**EN**:
|
||||
- Always use Prisma parameterized queries (automatic)
|
||||
- Never use string concatenation for queries
|
||||
- Validate and sanitize all inputs
|
||||
|
||||
**VI**:
|
||||
- Luôn sử dụng truy vấn tham số hóa của Prisma (tự động)
|
||||
- Không bao giờ sử dụng nối chuỗi cho truy vấn
|
||||
- Xác thực và làm sạch tất cả đầu vào
|
||||
|
||||
## Examples from Project / Ví Dụ Từ Dự Án
|
||||
|
||||
### Authentication Middleware / Middleware Xác Thực
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/auth.middleware.ts` for complete authentication implementation.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/auth.middleware.ts` để có implementation xác thực hoàn chỉnh.
|
||||
|
||||
### RBAC Middleware / Middleware RBAC
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/rbac.middleware.ts` for permission-based authorization.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/rbac.middleware.ts` để có phân quyền dựa trên quyền.
|
||||
|
||||
### Validation Middleware / Middleware Xác Thực
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/validation.middleware.ts` for input validation patterns.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/validation.middleware.ts` để có các mẫu xác thực đầu vào.
|
||||
|
||||
### Rate Limiting / Giới Hạn Tốc Độ
|
||||
|
||||
**EN**: See `services/iam-service/src/middlewares/rate-limit.middleware.ts` for dynamic rate limiting.
|
||||
|
||||
**VI**: Xem `services/iam-service/src/middlewares/rate-limit.middleware.ts` để có giới hạn tốc độ động.
|
||||
|
||||
## Quick Reference / Tham Khảo Nhanh
|
||||
|
||||
### Security Checklist / Danh Sách Kiểm Tra Bảo Mật
|
||||
|
||||
**EN**: Before deploying any service:
|
||||
- [ ] All endpoints require authentication (except public)
|
||||
- [ ] Authorization checks implemented (RBAC/ABAC)
|
||||
- [ ] Input validation with Zod schemas
|
||||
- [ ] Rate limiting configured
|
||||
- [ ] Error messages sanitized (no info disclosure)
|
||||
- [ ] PII encrypted at rest
|
||||
- [ ] Passwords hashed with bcrypt (cost 12+)
|
||||
- [ ] Tokens hashed before storing
|
||||
- [ ] Secrets in environment variables (never hardcoded)
|
||||
- [ ] HTTPS enforced (TLS 1.2+)
|
||||
- [ ] CORS configured correctly
|
||||
- [ ] Security headers set (helmet)
|
||||
- [ ] Audit logging enabled
|
||||
- [ ] SQL injection prevented (use Prisma)
|
||||
- [ ] XSS prevention (input sanitization)
|
||||
- [ ] File upload validation
|
||||
- [ ] Security tests passing
|
||||
|
||||
**VI**: Trước khi triển khai bất kỳ service nào:
|
||||
- [ ] Tất cả endpoint yêu cầu xác thực (trừ public)
|
||||
- [ ] Kiểm tra phân quyền đã triển khai (RBAC/ABAC)
|
||||
- [ ] Xác thực đầu vào với Zod schemas
|
||||
- [ ] Giới hạn tốc độ đã cấu hình
|
||||
- [ ] Thông báo lỗi đã được làm sạch (không tiết lộ thông tin)
|
||||
- [ ] PII được mã hóa khi nghỉ
|
||||
- [ ] Mật khẩu được hash với bcrypt (chi phí 12+)
|
||||
- [ ] Token được hash trước khi lưu
|
||||
- [ ] Bí mật trong biến môi trường (không bao giờ hardcode)
|
||||
- [ ] HTTPS được bắt buộc (TLS 1.2+)
|
||||
- [ ] CORS được cấu hình đúng
|
||||
- [ ] Header bảo mật được đặt (helmet)
|
||||
- [ ] Ghi log kiểm toán được bật
|
||||
- [ ] SQL injection được ngăn chặn (sử dụng Prisma)
|
||||
- [ ] Ngăn chặn XSS (làm sạch đầu vào)
|
||||
- [ ] Xác thực tải lên tệp
|
||||
- [ ] Kiểm tra bảo mật đã vượt qua
|
||||
|
||||
## Related Skills / Skills Liên Quan
|
||||
|
||||
- **[Project Rules](./project-rules.md)** - Coding standards and architecture
|
||||
- **[API Design](./api-design.md)** - Secure API design patterns
|
||||
- **[Testing Patterns](./testing-patterns.md)** - Security testing
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
**EN**:
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
|
||||
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
|
||||
- [Express Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html)
|
||||
|
||||
**VI**:
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
|
||||
- [Thực Hành Bảo Mật Node.js](https://nodejs.org/en/docs/guides/security/)
|
||||
- [Thực Hành Bảo Mật Express](https://expressjs.com/en/advanced/best-practice-security.html)
|
||||
Reference in New Issue
Block a user