Tôi còn nhớ rõ lần đầu tiên deploy một ứng dụng AI production. Tưởng đâu mọi thứ đã ổn định, nhưng sáng hôm sau logs cho thấy chi phí API tăng vọt 300% chỉ trong một đêm. Sau nhiều đêm mất ngủ debug, tôi mới biết đó là Context Length Attack — một trong những lỗ hổng bảo mật phổ biến nhất mà developer mới thường bỏ qua. Bài viết này sẽ giúp bạn hiểu rõ và bảo vệ ứng dụng của mình từ con số 0.

Context Length Attack Là Gì? Giải Thích Đơn Giản Cho Người Mới

Trước khi đi sâu vào code, hãy hiểu đơn giản về context length. Khi bạn chat với AI, mô hình có giới hạn về lượng text nó có thể "nhớ" trong một lần giao tiếp. Con số này gọi là context window — ví dụ GPT-4 có context 128K tokens, Claude 200K tokens.

Context Length Attack xảy ra khi:

Với HolySheheep AI, chi phí chỉ từ $0.42/MTok (DeepSeek V3.2), nhưng một cuộc tấn công context length có thể khiến bạn mất hàng trăm đô chỉ trong vài phút.

Tại Sao Developer Mới Dễ Bị Tấn Công?

Tôi đã từng mắc sai lầm này và hiện tại tôi thấy rất nhiều bạn mới cũng vậy:

Triển Khai Phòng Chống: Từng Bước Một

Bước 1: Cài Đặt Môi Trường và Kết Nối HolySheep API

Đầu tiên, hãy tạo một project Node.js mới. Tôi khuyên bạn nên dùng Node.js hoặc Python vì hai ngôn ngữ này có thư viện hỗ trợ tốt nhất.

// Khởi tạo project Node.js
mkdir context-attack-prevention
cd context-attack-prevention
npm init -y

// Cài đặt dependencies cần thiết
npm install express @anthropic-ai/sdk dotenv
npm install --save-dev nodemon

Tiếp theo, tạo file .env để lưu API key một cách an toàn:

# File .env - TUYỆT ĐỐI không commit file này lên git
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
MAX_INPUT_TOKENS=4000
MAX_OUTPUT_TOKENS=2000
RATE_LIMIT_WINDOW=60000
RATE_LIMIT_MAX=10

Bước 2: Viết Hàm Validate và Đếm Tokens

Đây là phần quan trọng nhất. Tôi đã viết một utility module hoàn chỉnh để xử lý việc đếm tokens và validate input:

// token-utils.js - Utility module xử lý tokens
const AI21_TOKEN_RATIO = 0.75; // Approximate tokens for non-English
const ENGLISH_TOKEN_RATIO = 0.25; // 4 chars ≈ 1 token in English

/**
 * Đếm số tokens ước tính trong text
 * Cách tính đơn giản: tiếng Anh ~4 ký tự = 1 token
 * @param {string} text - Text cần đếm
 * @returns {number} - Số tokens ước tính
 */
function estimateTokens(text) {
    if (!text || typeof text !== 'string') {
        return 0;
    }
    
    // Loại bỏ whitespace thừa
    const cleanText = text.trim();
    
    if (cleanText.length === 0) {
        return 0;
    }
    
    // Cách 1: Đếm theo từ (chính xác hơn cho tiếng Anh)
    const words = cleanText.split(/\s+/).length;
    const wordBasedTokens = Math.ceil(words / 0.75);
    
    // Cách 2: Đếm theo ký tự (dự phòng)
    const charBasedTokens = Math.ceil(cleanText.length * ENGLISH_TOKEN_RATIO);
    
    // Trả về giá trị lớn hơn để đảm bảo an toàn
    return Math.max(wordBasedTokens, charBasedTokens);
}

/**
 * Validate input trước khi gửi đến API
 * @param {string} input - Input từ user
 * @param {object} config - Cấu hình giới hạn
 * @returns {object} - { valid: boolean, error?: string, tokens?: number }
 */
function validateInput(input, config = {}) {
    const {
        maxTokens = 4000,
        minTokens = 1,
        allowEmpty = false
    } = config;
    
    // Kiểm tra input rỗng
    if (!input || (typeof input === 'string' && input.trim().length === 0)) {
        if (allowEmpty) {
            return { valid: true, tokens: 0 };
        }
        return { 
            valid: false, 
            error: 'Input không được để trống' 
        };
    }
    
    // Kiểm tra kiểu dữ liệu
    if (typeof input !== 'string') {
        return { 
            valid: false, 
            error: 'Input phải là chuỗi văn bản (string)' 
        };
    }
    
    // Đếm tokens
    const tokenCount = estimateTokens(input);
    
    // Kiểm tra giới hạn tối thiểu
    if (tokenCount < minTokens) {
        return { 
            valid: false, 
            error: Input quá ngắn (tối thiểu ${minTokens} tokens) 
        };
    }
    
    // Kiểm tra giới hạn tối đa - QUAN TRỌNG NHẤT
    if (tokenCount > maxTokens) {
        return { 
            valid: false, 
            error: Input quá dài: ${tokenCount} tokens (tối đa ${maxTokens} tokens). Vui lòng rút ngắn tin nhắn.,
            tokens: tokenCount
        };
    }
    
    return { 
        valid: true, 
        tokens: tokenCount,
        warning: tokenCount > maxTokens * 0.8 
            ? 'Cảnh báo: Input gần đạt giới hạn' 
            : null
    };
}

/**
 * Truncate text đến số tokens cho phép
 * @param {string} text - Text cần truncate
 * @param {number} maxTokens - Số tokens tối đa
 * @returns {string} - Text đã được cắt bớt
 */
function truncateToTokenLimit(text, maxTokens) {
    const currentTokens = estimateTokens(text);
    
    if (currentTokens <= maxTokens) {
        return text;
    }
    
    // Ước tính số ký tự cần giữ lại
    const maxChars = Math.floor(maxTokens / ENGLISH_TOKEN_RATIO);
    
    // Cắt theo ký tự rồi đệm thêm buffer
    let truncated = text.substring(0, maxChars);
    
    // Đệm thêm một chút để đảm bảo dưới limit
    // (vì cách tính ước lượng có thể không chính xác 100%)
    while (estimateTokens(truncated + '...') > maxTokens && truncated.length > 0) {
        truncated = truncated.slice(0, -100);
    }
    
    return truncated.trim() + (truncated.length < text.length ? '...' : '');
}

module.exports = {
    estimateTokens,
    validateInput,
    truncateToTokenLimit
};

Bước 3: Triển Khai Rate Limiting và Rate Limiter Thông Minh

Rate limiting không chỉ là giới hạn số request — bạn cần phát hiện và ngăn chặn các mẫu tấn công phức tạp. Tôi đã implement một hệ thống phát hiện thông minh:

// rate-limiter.js - Hệ thống rate limiting thông minh
const requestHistory = new Map();
const tokenUsageHistory = new Map();

class SmartRateLimiter {
    constructor(config = {}) {
        // Cấu hình mặc định
        this.windowMs = config.windowMs || 60000; // 1 phút
        this.maxRequests = config.maxRequests || 10; // 10 request/phút
        this.maxTokensPerWindow = config.maxTokensPerWindow || 50000; // 50K tokens/phút
        this.blockDurationMs = config.blockDurationMs || 300000; // Block 5 phút
        
        // Mapping lưu trữ
        this.requestCounts = new Map();
        this.tokenCounts = new Map();
        this.blockedIdentifiers = new Map();
        
        // Cleanup interval
        this.cleanupInterval = setInterval(() => this.cleanup(), this.windowMs);
    }
    
    /**
     * Lấy identifier cho request (IP, user ID, API key prefix)
     */
    getIdentifier(req) {
        // Ưu tiên user ID nếu có, không thì dùng IP
        return req.user?.id || req.ip || req.connection.remoteAddress || 'unknown';
    }
    
    /**
     * Kiểm tra xem request có bị block không
     */
    isBlocked(identifier) {
        const blockInfo = this.blockedIdentifiers.get(identifier);
        if (!blockInfo) return false;
        
        if (Date.now() < blockInfo.unblockAt) {
            return true;
        }
        
        // Hết thời gian block, xóa
        this.blockedIdentifiers.delete(identifier);
        return false;
    }
    
    /**
     * Block một identifier
     */
    block(identifier, reason = 'Rate limit exceeded') {
        const blockInfo = {
            reason,
            blockedAt: Date.now(),
            unblockAt: Date.now() + this.blockDurationMs
        };
        this.blockedIdentifiers.set(identifier, blockInfo);
        console.warn([RATE LIMIT] Blocked ${identifier}: ${reason});
    }
    
    /**
     * Check và record request
     * @returns {object} { allowed: boolean, reason?: string }
     */
    checkAndRecord(req, tokenCount = 0) {
        const identifier = this.getIdentifier(req);
        
        // Kiểm tra block
        if (this.isBlocked(identifier)) {
            const blockInfo = this.blockedIdentifiers.get(identifier);
            const remainingMs = blockInfo.unblockAt - Date.now();
            return {
                allowed: false,
                reason: Tạm thời bị block. Thử lại sau ${Math.ceil(remainingMs / 1000)} giây.,
                blocked: true
            };
        }
        
        const now = Date.now();
        
        // Khởi tạo hoặc reset counters nếu cửa sổ đã hết
        if (!this.requestCounts.has(identifier)) {
            this.requestCounts.set(identifier, { count: 0, windowStart: now });
        }
        
        if (!this.tokenCounts.has(identifier)) {
            this.tokenCounts.set(identifier, { tokens: 0, windowStart: now });
        }
        
        const requestInfo = this.requestCounts.get(identifier);
        const tokenInfo = this.tokenCounts.get(identifier);
        
        // Reset nếu cửa sổ đã hết
        if (now - requestInfo.windowStart > this.windowMs) {
            requestInfo.count = 0;
            requestInfo.windowStart = now;
        }
        
        if (now - tokenInfo.windowStart > this.windowMs) {
            tokenInfo.tokens = 0;
            tokenInfo.windowStart = now;
        }
        
        // Kiểm tra giới hạn request
        if (requestInfo.count >= this.maxRequests) {
            // Block nếu vi phạm nhiều lần
            this.block(identifier, 'Too many requests');
            return {
                allowed: false,
                reason: 'Đã vượt quá giới hạn request. Tài khoản tạm thời bị khóa.',
                blocked: true
            };
        }
        
        // Kiểm tra giới hạn tokens
        if (tokenInfo.tokens + tokenCount > this.maxTokensPerWindow) {
            return {
                allowed: false,
                reason: Sẽ vượt quá giới hạn tokens (${tokenInfo.tokens + tokenCount}/${this.maxTokensPerWindow})
            };
        }
        
        // Record request
        requestInfo.count++;
        tokenInfo.tokens += tokenCount;
        
        // Log để theo dõi
        console.log([RATE LIMIT] ${identifier}: ${requestInfo.count}/${this.maxRequests} requests, ${tokenInfo.tokens}/${this.maxTokensPerWindow} tokens);
        
        return {
            allowed: true,
            remainingRequests: this.maxRequests - requestInfo.count,
            remainingTokens: this.maxTokensPerWindow - tokenInfo.tokens
        };
    }
    
    /**
     * Cleanup old entries
     */
    cleanup() {
        const now = Date.now();
        
        // Cleanup request counts
        for (const [id, info] of this.requestCounts) {
            if (now - info.windowStart > this.windowMs * 2) {
                this.requestCounts.delete(id);
            }
        }
        
        // Cleanup token counts
        for (const [id, info] of this.tokenCounts) {
            if (now - info.windowStart > this.windowMs * 2) {
                this.tokenCounts.delete(id);
            }
        }
        
        // Cleanup blocks
        for (const [id, info] of this.blockedIdentifiers) {
            if (now > info.unblockAt) {
                this.blockedIdentifiers.delete(id);
            }
        }
    }
    
    /**
     * Destroy rate limiter
     */
    destroy() {
        clearInterval(this.cleanupInterval);
        this.requestCounts.clear();
        this.tokenCounts.clear();
        this.blockedIdentifiers.clear();
    }
}

module.exports = SmartRateLimiter;

Bước 4: Tạo API Server Hoàn Chỉnh Với HolySheep

Bây giờ, hãy kết hợi tất cả lại trong một Express server hoàn chỉnh. Đây là server tôi đã dùng trong production và nó đã ngăn chặn hàng ngàn cuộc tấn công:

// server.js - API Server hoàn chỉnh với bảo mật
require('dotenv').config();
const express = require('express');
const { validateInput, estimateTokens, truncateToTokenLimit } = require('./token-utils');
const SmartRateLimiter = require('./rate-limiter');

// Import HolySheep SDK - ĐÂY LÀ API CHÍNH THỨC
// Tuyệt đối KHÔNG dùng api.openai.com
const HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1';
const HOLYSHEEP_API_KEY = process.env.HOLYSHEEP_API_KEY;

const app = express();
app.use(express.json({ limit: '10kb' })); // Giới hạn JSON payload
app.use(express.urlencoded({ extended: true, limit: '10kb' }));

// Khởi tạo rate limiter với cấu hình bảo mật
const rateLimiter = new SmartRateLimiter({
    windowMs: 60000,           // 1 phút
    maxRequests: 10,           // 10 request/phút/IP
    maxTokensPerWindow: 20000, // 20K tokens/phút/IP
    blockDurationMs: 300000    // Block 5 phút nếu vi phạm
});

// Cấu hình bảo mật
const SECURITY_CONFIG = {
    maxInputTokens: 4000,      // Giới hạn input 4K tokens
    maxOutputTokens: 2000,     // Giới hạn output 2K tokens
    maxHistoryMessages: 10,    // Giới hạn lịch sử chat
    allowSystemPromptOverride: false, // Ngăn chặn prompt injection
    trustedRoles: ['admin']    // Chỉ admin mới được override
};

// Middleware logging request
app.use((req, res, next) => {
    const timestamp = new Date().toISOString();
    console.log([${timestamp}] ${req.method} ${req.path} - IP: ${req.ip});
    next();
});

// Health check endpoint
app.get('/health', (req, res) => {
    res.json({ 
        status: 'healthy', 
        timestamp: Date.now(),
        rateLimiterActive: true
    });
});

// Endpoint chat chính với bảo mật
app.post('/api/chat', async (req, res) => {
    try {
        const { message, systemPrompt, conversationHistory = [] } = req.body;
        
        // ===== LAYER 1: Rate Limiting =====
        const rateCheck = rateLimiter.checkAndRecord(req, estimateTokens(message));
        if (!rateCheck.allowed) {
            return res.status(429).json({
                error: rateCheck.reason,
                code: 'RATE_LIMIT_EXCEEDED',
                blocked: rateCheck.blocked || false
            });
        }
        
        // ===== LAYER 2: Input Validation =====
        const validation = validateInput(message, {
            maxTokens: SECURITY_CONFIG.maxInputTokens,
            minTokens: 1
        });
        
        if (!validation.valid) {
            return res.status(400).json({
                error: validation.error,
                code: 'INVALID_INPUT',
                tokens: validation.tokens
            });
        }
        
        // ===== LAYER 3: Conversation History Validation =====
        if (conversationHistory.length > SECURITY_CONFIG.maxHistoryMessages) {
            return res.status(400).json({
                error: Quá nhiều tin nhắn trong lịch sử (tối đa ${SECURITY_CONFIG.maxHistoryMessages}),
                code: 'HISTORY_TOO_LONG'
            });
        }
        
        // Kiểm tra tổng tokens của history
        let totalHistoryTokens = 0;
        for (const msg of conversationHistory) {
            totalHistoryTokens += estimateTokens(msg.content || '');
        }
        if (totalHistoryTokens > SECURITY_CONFIG.maxInputTokens * 2) {
            return res.status(400).json({
                error: 'Lịch sử hội thoại quá dài. Vui lòng bắt đầu cuộc trò chuyện mới.',
                code: 'HISTORY_EXCEEDS_LIMIT'
            });
        }
        
        // ===== LAYER 4: System Prompt Protection =====
        let finalSystemPrompt = 'Bạn là một trợ lý AI hữu ích.';
        if (systemPrompt && SECURITY_CONFIG.allowSystemPromptOverride) {
            // Chỉ cho phép override nếu được cấu hình và user có role phù hợp
            const userRole = req.user?.role;
            if (userRole && SECURITY_CONFIG.trustedRoles.includes(userRole)) {
                finalSystemPrompt = systemPrompt;
                console.log([SECURITY] System prompt overridden by trusted role: ${userRole});
            } else {
                console.warn([SECURITY] Unauthorized system prompt override attempt from ${req.ip});
            }
        }
        
        // ===== LAYER 5: Prompt Injection Detection =====
        const injectionPatterns = [
            /ignore (previous|above|all) (instructions|prompts?)/i,
            /disregard (your|this) (instruction|system prompt)/i,
            /you are now/i,
            /forget (everything|all previous)/i,
            /new (instruction|rule|prompt):/i
        ];
        
        for (const pattern of injectionPatterns) {
            if (pattern.test(message)) {
                console.warn([SECURITY] Possible prompt injection detected from ${req.ip}: ${message.substring(0, 100)});
                // Vẫn cho phép nhưng log để monitor
            }
        }
        
        // ===== LAYER 6: Build Request to HolySheep =====
        const messages = [
            { role: 'system', content: finalSystemPrompt },
            ...conversationHistory.slice(-SECURITY_CONFIG.maxHistoryMessages),
            { role: 'user', content: truncateToTokenLimit(message, SECURITY_CONFIG.maxInputTokens) }
        ];
        
        // ===== LAYER 7: Call HolySheep API =====
        const response = await fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
            method: 'POST',
            headers: {
                'Authorization': Bearer ${HOLYSHEEP_API_KEY},
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                model: 'gpt-4.1', // Hoặc model khác: claude-sonnet-4.5, gemini-2.5-flash, deepseek-v3.2
                messages: messages,
                max_tokens: SECURITY_CONFIG.maxOutputTokens,
                temperature: 0.7
            })
        });
        
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            console.error([HOLYSHEEP] API Error: ${response.status}, errorData);
            
            return res.status(response.status).json({
                error: 'Lỗi khi gọi AI service',
                code: 'AI_SERVICE_ERROR'
            });
        }
        
        const data = await response.json();
        
        // ===== LAYER 8: Response Validation =====
        const aiResponse = data.choices?.[0]?.message?.content;
        if (!aiResponse) {
            return res.status(500).json({
                error: 'Không nhận được phản hồi từ AI',
                code: 'EMPTY_RESPONSE'
            });
        }
        
        // Trả về response
        res.json({
            response: aiResponse,
            usage: data.usage ? {
                inputTokens: data.usage.prompt_tokens,
                outputTokens: data.usage.completion_tokens,
                totalTokens: data.usage.total_tokens
            } : null,
            rateLimit: rateCheck
        });
        
    } catch (error) {
        console.error('[ERROR] Chat endpoint error:', error);
        res.status(500).json({
            error: 'Đã xảy ra lỗi nội bộ. Vui lòng thử lại sau.',
            code: 'INTERNAL_ERROR'
        });
    }
});

// Error handling middleware
app.use((err, req, res, next) => {
    console.error('[ERROR] Unhandled error:', err);
    res.status(500).json({
        error: 'Lỗi hệ thống',
        code: 'UNHANDLED_ERROR'
    });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log([SERVER] Running on port ${PORT});
    console.log([HOLYSHEEP] API Endpoint: ${HOLYSHEEP_BASE_URL});
    console.log([SECURITY] Max input tokens: ${SECURITY_CONFIG.maxInputTokens});
});

// Graceful shutdown
process.on('SIGTERM', () => {
    console.log('[SERVER] Shutting down gracefully...');
    rateLimiter.destroy();
    process.exit(0);
});

Giải Thích Chi Tiết Từng Lớp Bảo Mật

Tôi đã implement 8 lớp bảo mật trong code trên. Hãy để tôi giải thích tại sao mỗi lớp lại quan trọng:

Lớp 1: Rate Limiting — Ngăn Chặn Tấn Công Số Lượng

Kẻ tấn công sẽ gửi hàng trăm request nhỏ liên tục để tiêu tốn credits của bạn. Rate limiter theo dõi mỗi IP và block nếu vượt ngưỡng.

Lớp 2-3: Input Validation — Ngăn Chặn Input Quá Dài

Context length attack chính là gửi input gần bằng context limit. Mỗi token bạn gửi đi đều phải trả tiền. Với HolySheep, giá chỉ từ $0.42/MTok, nhưng 1 triệu tokens = $420 — một cuộc tấn công có thể tiêu tốn số đó trong vài phút.

Lớp 4-5: Prompt Injection Protection

Kẻ tấn công có thể cố gắng thay đổi system prompt để lấy thông tin nhạy cảm hoặc bypass logic bảo mật.

Lớp 6-8: API Call và Response Handling

Luôn validate response từ API. Đôi khi model có thể trả về nội dung không mong muốn.

Bảng So Sánh Chi Phí: HolySheep vs Providers Khác

Một trong những lý do tôi chọn HolySheep cho production là giá cả cạnh tranh nhất thị trường:

Với tỷ giá ¥1=$1 và hỗ trợ WeChat/Alipay, HolySheep đặc biệt thuận tiện cho developers Châu Á. Độ trễ trung bình dưới 50ms giúp ứng dụng responsive hơn.

Hướng Dẫn Deploy và Monitor

Sau khi code xong, bạn cần deploy và monitor. Tôi khuyên dùng:

# Dockerfile cho production deployment
FROM node:20-alpine

WORKDIR /app

Copy package files

COPY package*.json ./ RUN npm ci --only=production

Copy source code

COPY . .

Create non-root user

RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 USER nodejs EXPOSE 3000 CMD ["node", "server.js"]

Để monitor, tôi suggest thêm logging cho các attack patterns:

// monitor.js - Logging và alerting
const attackLog = [];

function logSecurityEvent(event) {
    const logEntry = {
        timestamp: Date.now(),
        ...event
    };
    attackLog.push(logEntry);
    
    // Giữ chỉ 1000 entries gần nhất
    if (attackLog.length > 1000) {
        attackLog.shift();
    }
    
    // Console log cho production debugging
    console.error('[SECURITY EVENT]', JSON.stringify(logEntry));
    
    // Gửi alert nếu có nhiều attack liên tục
    if (attackLog.length > 50 && attackLog[attackLog.length - 50].timestamp > Date.now() - 60000) {
        sendAlert(Cảnh báo: ${attackLog.length} sự kiện bảo mật trong 1 phút);
    }
}

function sendAlert(message) {
    // Implement alert qua email, Slack, PagerDuty...
    console.error('[ALERT]', message);
}

module.exports = { logSecurityEvent, attackLog };

Lỗi Thường Gặp và Cách Khắc Phục

Lỗi 1: "413 Payload Too Large" hoặc Input Bị Cắt

Nguyên nhân: Input từ user vượt quá giới hạn context hoặc payload limit của server.

// Cách khắc phục: Cấu hình đúng maxTokens và thêm middleware xử lý
// Trong server.js, thêm:

// Tăng limit cho JSON parsing nếu cần (nhưng vẫn giới hạn hợp lý)
app.use(express.json({ limit: '50kb' }));

// Hoặc sử dụng custom error handler cho payload too large
app.use((err, req, res, next) => {
    if (err.type === 'entity.too.large') {
        return res.status(413).json({
            error: 'Dữ liệu gửi lên quá lớn. Vui lòng gửi tin nhắn ngắn hơn.',
            code: 'PAYLOAD_TOO_LARGE',
            maxSize: '50KB'
        });
    }
    next(err);
});

// Trong client, xử lý response:
fetch('/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message: userInput })
})
.then(response => {
    if (response.status === 413) {
        alert('Tin nhắn quá dài. Vui lòng chia nhỏ thành nhiều tin nhắn.');
        return;
    }
    return response.json();
});

Lỗi 2: "429 Rate Limit Exceeded" Mặc Dù User Không Spam

Nguyên nhân: Nhiều users chia sẻ same IP (proxy, corporate network) hoặc client gửi duplicate requests.

// Cách khắc phục: Implement request deduplication và per-user rate limiting

// Thêm deduplication cache
const recentRequests = new Map();
const DEDUP_WINDOW_MS = 5000; // 5 giây

function isDuplicateRequest(reqId, userId) {
    const key = ${userId}:${reqId};
    const lastRequest = recentRequests.get(key);
    
    if (lastRequest && Date.now() - lastRequest < DEDUP_WINDOW_MS) {
        return true;
    }
    
    recentRequests.set(key, Date.now());
    return false;
}

// Sử dụng user-specific rate limit thay vì IP-based
const rateLimiter = new SmartRateLimiter({
    windowMs: 60000,
    maxRequests: 20,        // Tăng limit per user
    maxTokensPerWindow: 40000,
    blockDurationMs: 120000  // Giảm block duration
});

// Trong endpoint:
app.post('/api/chat', async (req, res) => {
    const userId = req.user?.id || req.headers['x-user-id'];
    const requestId =