{"product_id":"bảo-mật-mcp-server-authentication-authorization-va-best-practices","title":"Bảo mật MCP Server — Authentication, Authorization và Best Practices","description":"\n\u003cp\u003eModel Context Protocol (MCP) mở ra khả năng mạnh mẽ cho Claude khi kết nối với hệ thống bên ngoài — database, file system, API, dịch vụ cloud. Nhưng sức mạnh đó đi kèm rủi ro bảo mật nghiêm trọng nếu không được kiểm soát. Một MCP Server thiếu bảo mật có thể trở thành cánh cửa cho tấn công: rò rỉ dữ liệu, thực thi mã độc, leo thang quyền. Bài viết này trình bày mô hình bảo mật MCP và các biện pháp cần áp dụng cho mọi môi trường, đặc biệt là production.\u003c\/p\u003e\n\n\u003ch2\u003eMô hình bảo mật MCP\u003c\/h2\u003e\n\u003cp\u003eMCP sử dụng mô hình bảo mật nhiều lớp:\u003c\/p\u003e\n\u003cul\u003e\n  \u003cli\u003e\n\u003cstrong\u003eTransport layer:\u003c\/strong\u003e Bảo mật kênh truyền dữ liệu giữa MCP client (Claude) và MCP server\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eAuthentication:\u003c\/strong\u003e Xác minh danh tính của client kết nối đến server\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eAuthorization:\u003c\/strong\u003e Kiểm soát client được phép làm gì (tool nào, resource nào)\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eTool sandboxing:\u003c\/strong\u003e Giới hạn phạm vi tác động của từng tool\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eData protection:\u003c\/strong\u003e Bảo vệ dữ liệu nhạy cảm không bị rò rỉ qua LLM\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eThreat model cho MCP\u003c\/h3\u003e\n\u003cp\u003eTrước khi triển khai bảo mật, cần hiểu các mối đe dọa chính:\u003c\/p\u003e\n\u003cul\u003e\n  \u003cli\u003e\n\u003cstrong\u003ePrompt injection:\u003c\/strong\u003e Kẻ tấn công chèn hướng dẫn độc hại vào dữ liệu mà Claude xử lý, khiến Claude gọi tool với tham số nguy hiểm\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eData exfiltration:\u003c\/strong\u003e Dữ liệu nhạy cảm từ hệ thống nội bộ bị gửi ra ngoài qua phản hồi của LLM\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003ePrivilege escalation:\u003c\/strong\u003e Kẻ tấn công lợi dụng quyền của MCP Server để truy cập tài nguyên vượt phạm vi cho phép\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eDenial of service:\u003c\/strong\u003e Query hoặc thao tác nặng làm sập hệ thống backend\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eMan-in-the-middle:\u003c\/strong\u003e Chặn bắt dữ liệu truyền giữa client và server khi dùng transport không mã hóa\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch2\u003eBảo mật Transport: stdio vs SSE vs Streamable HTTP\u003c\/h2\u003e\n\u003cp\u003eMCP hỗ trợ nhiều phương thức truyền tải (transport). Mỗi phương thức có đặc điểm bảo mật khác nhau:\u003c\/p\u003e\n\n\u003ch3\u003estdio (Standard I\/O)\u003c\/h3\u003e\n\u003cp\u003eMCP Server chạy như một process con, giao tiếp qua stdin\/stdout.\u003c\/p\u003e\n\u003cul\u003e\n  \u003cli\u003e\n\u003cstrong\u003eƯu điểm:\u003c\/strong\u003e Bảo mật cao nhất vì dữ liệu không đi qua mạng. Không cần cấu hình TLS. Process chạy với quyền của user hiện tại.\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eHạn chế:\u003c\/strong\u003e Chỉ hoạt động trên cùng máy. Không chia sẻ được giữa nhiều client.\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003ePhù hợp:\u003c\/strong\u003e Development, sử dụng cá nhân trên máy local\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eSSE (Server-Sent Events)\u003c\/h3\u003e\n\u003cp\u003eGiao tiếp qua HTTP với SSE cho streaming.\u003c\/p\u003e\n\u003cul\u003e\n  \u003cli\u003e\n\u003cstrong\u003eƯu điểm:\u003c\/strong\u003e Hỗ trợ remote, nhiều client kết nối cùng lúc\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eHạn chế:\u003c\/strong\u003e Cần cấu hình HTTPS\/TLS. Cần authentication riêng. SSE chỉ hỗ trợ giao tiếp một chiều (server-to-client), cần kết hợp với HTTP POST cho chiều ngược lại.\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003ePhù hợp:\u003c\/strong\u003e Triển khai nội bộ trong mạng tin cậy\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eStreamable HTTP\u003c\/h3\u003e\n\u003cp\u003eTransport mới nhất, sử dụng HTTP thuần với khả năng streaming.\u003c\/p\u003e\n\u003cul\u003e\n  \u003cli\u003e\n\u003cstrong\u003eƯu điểm:\u003c\/strong\u003e Linh hoạt nhất, hoạt động qua firewall và proxy. Hỗ trợ HTTP\/2 và giao tiếp hai chiều. Dễ tích hợp với hạ tầng web hiện có (load balancer, CDN, WAF).\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eHạn chế:\u003c\/strong\u003e Cần cấu hình bảo mật đầy đủ: TLS, authentication, CORS\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003ePhù hợp:\u003c\/strong\u003e Production, triển khai từ xa, multi-tenant\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eCấu hình TLS cho remote transport\u003c\/h3\u003e\n\u003cpre\u003e\u003ccode\u003e\/\/ MCP Server với HTTPS (Streamable HTTP)\nconst https = require(\"https\");\nconst fs = require(\"fs\");\nconst { McpServer } = require(\"@modelcontextprotocol\/sdk\/server\/mcp.js\");\nconst { StreamableHTTPServerTransport } =\n  require(\"@modelcontextprotocol\/sdk\/server\/streamableHttp.js\");\n\nconst server = new McpServer({\n  name: \"secure-mcp\",\n  version: \"1.0.0\"\n});\n\n\/\/ TLS configuration\nconst httpsOptions = {\n  key: fs.readFileSync(\"\/path\/to\/private-key.pem\"),\n  cert: fs.readFileSync(\"\/path\/to\/certificate.pem\"),\n  ca: fs.readFileSync(\"\/path\/to\/ca-bundle.pem\"),\n  minVersion: \"TLSv1.3\"  \/\/ Chỉ cho phép TLS 1.3\n};\n\nconst httpsServer = https.createServer(httpsOptions, app);\nhttpsServer.listen(8443);\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eAuthentication: Xác thực danh tính\u003c\/h2\u003e\n\n\u003ch3\u003eAPI Key Authentication\u003c\/h3\u003e\n\u003cp\u003ePhương pháp đơn giản nhất, phù hợp cho sử dụng nội bộ hoặc ít client:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003e\/\/ Middleware xác thực API key\nfunction authenticateApiKey(req, res, next) {\n  const apiKey = req.headers[\"x-api-key\"];\n\n  if (!apiKey) {\n    return res.status(401).json({ error: \"Missing API key\" });\n  }\n\n  \/\/ So sánh với danh sách key hợp lệ\n  \/\/ Lưu ý: dùng timing-safe comparison để chống timing attack\n  const crypto = require(\"crypto\");\n  const validKeys = process.env.MCP_API_KEYS.split(\",\");\n  const isValid = validKeys.some(key =\u0026gt;\n    crypto.timingSafeEqual(\n      Buffer.from(apiKey),\n      Buffer.from(key)\n    )\n  );\n\n  if (!isValid) {\n    return res.status(403).json({ error: \"Invalid API key\" });\n  }\n\n  \/\/ Gán thông tin client cho request\n  req.clientId = getClientIdFromKey(apiKey);\n  next();\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch3\u003eOAuth 2.1 Authentication\u003c\/h3\u003e\n\u003cp\u003eMCP specification khuyến nghị OAuth 2.1 cho xác thực trong môi trường production, đặc biệt với remote transport. OAuth 2.1 cải tiến so với OAuth 2.0:\u003c\/p\u003e\n\u003cul\u003e\n  \u003cli\u003eBắt buộc PKCE (Proof Key for Code Exchange) cho mọi client\u003c\/li\u003e\n  \u003cli\u003eLoại bỏ implicit grant flow (kém bảo mật)\u003c\/li\u003e\n  \u003cli\u003eBắt buộc exact redirect URI matching\u003c\/li\u003e\n  \u003cli\u003eRefresh token phải là one-time use hoặc sender-constrained\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003cpre\u003e\u003ccode\u003e\/\/ OAuth 2.1 middleware cho MCP Server\nconst { verifyAccessToken } = require(\".\/auth\/oauth\");\n\nasync function authenticateOAuth(req, res, next) {\n  const authHeader = req.headers.authorization;\n\n  if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n    return res.status(401).json({\n      error: \"unauthorized\",\n      error_description: \"Bearer token required\"\n    });\n  }\n\n  const token = authHeader.split(\" \")[1];\n\n  try {\n    const tokenInfo = await verifyAccessToken(token);\n\n    \/\/ Kiểm tra token chưa hết hạn\n    if (tokenInfo.exp \u0026lt; Date.now() \/ 1000) {\n      return res.status(401).json({\n        error: \"token_expired\",\n        error_description: \"Access token has expired\"\n      });\n    }\n\n    \/\/ Kiểm tra scope\n    req.clientId = tokenInfo.client_id;\n    req.scopes = tokenInfo.scope.split(\" \");\n    next();\n  } catch (error) {\n    return res.status(403).json({\n      error: \"invalid_token\",\n      error_description: \"Token verification failed\"\n    });\n  }\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eAuthorization: Phân quyền tool\u003c\/h2\u003e\n\u003cp\u003eKhông phải mọi client đều được phép sử dụng mọi tool. Hệ thống phân quyền cần kiểm soát:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e\/\/ Bảng phân quyền theo role\nconst PERMISSIONS = {\n  analyst: {\n    tools: [\"list_tables\", \"describe_table\", \"run_query\"],\n    allowedTables: [\"orders\", \"products\", \"categories\"],\n    maxRowsPerQuery: 1000\n  },\n  support: {\n    tools: [\"search_customer\", \"get_order_status\"],\n    allowedTables: [\"customers\", \"orders\"],\n    maxRowsPerQuery: 50\n  },\n  admin: {\n    tools: [\"*\"],  \/\/ Tất cả tools\n    allowedTables: [\"*\"],\n    maxRowsPerQuery: 5000\n  }\n};\n\nfunction authorizeToolCall(clientId, toolName, params) {\n  const role = getClientRole(clientId);\n  const perms = PERMISSIONS[role];\n\n  if (!perms) {\n    return { allowed: false, reason: \"Unknown role\" };\n  }\n\n  \/\/ Kiểm tra tool được phép\n  if (perms.tools[0] !== \"*\" \u0026amp;\u0026amp; !perms.tools.includes(toolName)) {\n    return {\n      allowed: false,\n      reason: \"Tool \" + toolName + \" không được phép cho role \" + role\n    };\n  }\n\n  return { allowed: true, limits: perms };\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eTool Permission Sandboxing\u003c\/h2\u003e\n\u003cp\u003eMỗi tool cần được sandbox — giới hạn phạm vi tác động để giảm thiểu rủi ro khi bị khai thác:\u003c\/p\u003e\n\n\u003ch3\u003eNguyên tắc thiết kế tool an toàn\u003c\/h3\u003e\n\u003cul\u003e\n  \u003cli\u003e\n\u003cstrong\u003eLeast privilege:\u003c\/strong\u003e Mỗi tool chỉ có quyền tối thiểu cần thiết. Tool đọc dữ liệu không có quyền ghi. Tool ghi dữ liệu chỉ ghi vào bảng cụ thể.\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eInput validation:\u003c\/strong\u003e Validate mọi tham số đầu vào. Dùng schema validation (zod, joi) thay vì kiểm tra thủ công.\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eOutput filtering:\u003c\/strong\u003e Loại bỏ dữ liệu nhạy cảm khỏi kết quả trước khi trả về Claude.\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eRate limiting:\u003c\/strong\u003e Giới hạn tần suất gọi tool để chống abuse.\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eIdempotency:\u003c\/strong\u003e Tool ghi dữ liệu nên idempotent — gọi nhiều lần cho cùng kết quả.\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003cpre\u003e\u003ccode\u003e\/\/ Ví dụ sandbox cho file system tool\nconst path = require(\"path\");\n\nconst SANDBOX_ROOT = \"\/data\/shared\";\nconst BLOCKED_EXTENSIONS = [\".env\", \".key\", \".pem\", \".p12\", \".pfx\"];\nconst MAX_FILE_SIZE = 10 * 1024 * 1024; \/\/ 10MB\n\nfunction validateFilePath(filePath) {\n  \/\/ Resolve path tuyệt đối\n  const resolved = path.resolve(SANDBOX_ROOT, filePath);\n\n  \/\/ Kiểm tra path traversal (..\/..\/etc\/passwd)\n  if (!resolved.startsWith(SANDBOX_ROOT)) {\n    throw new Error(\"Access denied: path outside sandbox\");\n  }\n\n  \/\/ Kiểm tra extension nhạy cảm\n  const ext = path.extname(resolved).toLowerCase();\n  if (BLOCKED_EXTENSIONS.includes(ext)) {\n    throw new Error(\"Access denied: sensitive file type\");\n  }\n\n  return resolved;\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eNgăn chặn rò rỉ dữ liệu (Data Exfiltration Prevention)\u003c\/h2\u003e\n\u003cp\u003eMột rủi ro quan trọng khi kết nối LLM với hệ thống nội bộ: dữ liệu nhạy cảm có thể bị rò rỉ qua phản hồi của Claude. Các biện pháp phòng ngừa:\u003c\/p\u003e\n\n\u003ch3\u003eLọc dữ liệu nhạy cảm trước khi trả về\u003c\/h3\u003e\n\u003cpre\u003e\u003ccode\u003e\/\/ Danh sách pattern dữ liệu nhạy cảm cần masking\nconst SENSITIVE_PATTERNS = [\n  {\n    name: \"credit_card\",\n    regex: \/d{4}[s-]?d{4}[s-]?d{4}[s-]?d{4}\/g,\n    mask: \"****-****-****-XXXX\"\n  },\n  {\n    name: \"phone_vn\",\n    regex: \/(0[3-9]d{8})\/g,\n    mask: (match) =\u0026gt; match.slice(0, 4) + \"***\" + match.slice(-3)\n  },\n  {\n    name: \"email\",\n    regex: \/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Z]{2,}\/gi,\n    mask: (match) =\u0026gt; {\n      const [local, domain] = match.split(\"@\");\n      return local.slice(0, 2) + \"***@\" + domain;\n    }\n  },\n  {\n    name: \"cmnd_cccd\",\n    regex: \/d{9}(d{3})?\/g,\n    mask: \"***XXXXXX\"\n  }\n];\n\nfunction sanitizeOutput(data) {\n  let text = typeof data === \"string\" ? data : JSON.stringify(data);\n  for (const pattern of SENSITIVE_PATTERNS) {\n    text = text.replace(pattern.regex, (match) =\u0026gt;\n      typeof pattern.mask === \"function\" ? pattern.mask(match) : pattern.mask\n    );\n  }\n  return text;\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch3\u003eKiểm soát dữ liệu đầu ra theo column\u003c\/h3\u003e\n\u003cpre\u003e\u003ccode\u003e\/\/ Loại bỏ column nhạy cảm khỏi kết quả query\nconst SENSITIVE_COLUMNS = [\n  \"password\", \"password_hash\", \"secret\",\n  \"api_key\", \"token\", \"ssn\", \"credit_card\",\n  \"cmnd\", \"cccd\", \"bank_account\"\n];\n\nfunction filterSensitiveColumns(rows) {\n  return rows.map(row =\u0026gt; {\n    const filtered = { ...row };\n    for (const col of SENSITIVE_COLUMNS) {\n      if (col in filtered) {\n        filtered[col] = \"[REDACTED]\";\n      }\n    }\n    return filtered;\n  });\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eAudit Logging\u003c\/h2\u003e\n\u003cp\u003eGhi log chi tiết mọi hoạt động qua MCP Server để phát hiện bất thường và phục vụ forensics:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e\/\/ Structured audit logging\nconst winston = require(\"winston\");\n\nconst auditLogger = winston.createLogger({\n  level: \"info\",\n  format: winston.format.json(),\n  defaultMeta: { service: \"mcp-server\" },\n  transports: [\n    new winston.transports.File({\n      filename: \"audit.log\",\n      maxsize: 50 * 1024 * 1024,  \/\/ 50MB\n      maxFiles: 30,\n      tailable: true\n    })\n  ]\n});\n\nfunction logToolCall(clientId, toolName, params, result, duration) {\n  auditLogger.info(\"tool_call\", {\n    timestamp: new Date().toISOString(),\n    clientId: clientId,\n    tool: toolName,\n    params: sanitizeParams(params),  \/\/ Không log password\/secret\n    resultSize: JSON.stringify(result).length,\n    rowCount: result.rowCount || null,\n    durationMs: duration,\n    success: true\n  });\n}\n\nfunction logToolError(clientId, toolName, params, error) {\n  auditLogger.error(\"tool_error\", {\n    timestamp: new Date().toISOString(),\n    clientId: clientId,\n    tool: toolName,\n    params: sanitizeParams(params),\n    error: error.message,\n    stack: error.stack\n  });\n}\n\n\/\/ Loại bỏ giá trị nhạy cảm trong params trước khi log\nfunction sanitizeParams(params) {\n  const safe = { ...params };\n  const sensitiveKeys = [\"password\", \"secret\", \"token\", \"key\"];\n  for (const key of sensitiveKeys) {\n    if (key in safe) safe[key] = \"[REDACTED]\";\n  }\n  return safe;\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eProduction Hardening Checklist\u003c\/h2\u003e\n\u003cp\u003eChecklist bảo mật trước khi triển khai MCP Server lên production:\u003c\/p\u003e\n\n\u003ch3\u003eTransport Security\u003c\/h3\u003e\n\u003cul\u003e\n  \u003cli\u003eSử dụng TLS 1.3 cho mọi remote transport\u003c\/li\u003e\n  \u003cli\u003eCertificate từ CA tin cậy (Let's Encrypt hoặc internal CA)\u003c\/li\u003e\n  \u003cli\u003eCấu hình HSTS header nếu dùng HTTP transport\u003c\/li\u003e\n  \u003cli\u003eDisable TLS 1.0, 1.1 và các cipher suite yếu\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eAuthentication\u003c\/h3\u003e\n\u003cul\u003e\n  \u003cli\u003eTriển khai OAuth 2.1 với PKCE cho multi-client\u003c\/li\u003e\n  \u003cli\u003eAPI key rotation policy (đổi key mỗi 90 ngày)\u003c\/li\u003e\n  \u003cli\u003eKhông hardcode credentials trong source code\u003c\/li\u003e\n  \u003cli\u003eSử dụng secret manager (HashiCorp Vault, AWS Secrets Manager)\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eAuthorization\u003c\/h3\u003e\n\u003cul\u003e\n  \u003cli\u003ePhân quyền theo role cho từng client\u003c\/li\u003e\n  \u003cli\u003eWhitelist tool thay vì blacklist\u003c\/li\u003e\n  \u003cli\u003eGiới hạn scope truy cập dữ liệu\u003c\/li\u003e\n  \u003cli\u003eReview quyền định kỳ (quarterly access review)\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eTool Security\u003c\/h3\u003e\n\u003cul\u003e\n  \u003cli\u003eInput validation cho mọi tham số tool\u003c\/li\u003e\n  \u003cli\u003eOutput sanitization loại bỏ dữ liệu nhạy cảm\u003c\/li\u003e\n  \u003cli\u003eRate limiting cho từng tool và từng client\u003c\/li\u003e\n  \u003cli\u003eTimeout cho mọi thao tác có thể chạy lâu\u003c\/li\u003e\n  \u003cli\u003eSandbox file system access\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eMonitoring\u003c\/h3\u003e\n\u003cul\u003e\n  \u003cli\u003eStructured audit logging cho mọi tool call\u003c\/li\u003e\n  \u003cli\u003eAlert khi phát hiện pattern bất thường (query đến bảng nhạy cảm, tần suất bất thường, lỗi xác thực liên tiếp)\u003c\/li\u003e\n  \u003cli\u003eDashboard theo dõi số lượng request, latency, error rate\u003c\/li\u003e\n  \u003cli\u003eLog retention tối thiểu 90 ngày\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eInfrastructure\u003c\/h3\u003e\n\u003cul\u003e\n  \u003cli\u003eChạy MCP Server trong container với non-root user\u003c\/li\u003e\n  \u003cli\u003eNetwork isolation: MCP Server chỉ kết nối đến các service cần thiết\u003c\/li\u003e\n  \u003cli\u003eKhông expose MCP Server ra public internet nếu không cần thiết\u003c\/li\u003e\n  \u003cli\u003eRegular security updates cho dependencies\u003c\/li\u003e\n  \u003cli\u003eDependency scanning (npm audit, Snyk)\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch2\u003eCấu hình rate limiting\u003c\/h2\u003e\n\u003cpre\u003e\u003ccode\u003e\/\/ Rate limiting middleware\nconst rateLimit = require(\"express-rate-limit\");\n\n\/\/ Giới hạn chung: 100 request\/phút\nconst generalLimiter = rateLimit({\n  windowMs: 60 * 1000,\n  max: 100,\n  message: { error: \"Rate limit exceeded. Try again later.\" }\n});\n\n\/\/ Giới hạn cho tool nhạy cảm: 10 request\/phút\nconst sensitiveLimiter = rateLimit({\n  windowMs: 60 * 1000,\n  max: 10,\n  keyGenerator: (req) =\u0026gt; req.clientId,\n  message: { error: \"Sensitive tool rate limit exceeded.\" }\n});\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003ePhòng chống Prompt Injection qua dữ liệu\u003c\/h2\u003e\n\u003cp\u003eMột rủi ro đặc thù với MCP: dữ liệu trả về từ tool có thể chứa hướng dẫn độc hại. Ví dụ, kẻ tấn công lưu prompt injection vào tên sản phẩm trong database. Khi Claude đọc dữ liệu này, có thể bị điều khiển.\u003c\/p\u003e\n\n\u003ch3\u003eBiện pháp phòng ngừa\u003c\/h3\u003e\n\u003cpre\u003e\u003ccode\u003e\/\/ Sanitize dữ liệu trả về từ tool trước khi gửi cho Claude\nfunction sanitizeToolOutput(data) {\n  const text = typeof data === \"string\" ? data : JSON.stringify(data);\n\n  \/\/ Loại bỏ các pattern prompt injection phổ biến\n  const suspiciousPatterns = [\n    \/ignores+(previous|above|all)s+instructions\/gi,\n    \/yous+ares+nows+\/gi,\n    \/systems*:s*\/gi,\n    \/[INST]\/gi,\n    \/\u0026lt;system\u0026gt;\/gi,\n    \/forgets+everything\/gi\n  ];\n\n  let cleaned = text;\n  for (const pattern of suspiciousPatterns) {\n    if (pattern.test(cleaned)) {\n      \/\/ Log cảnh báo\n      auditLogger.warn(\"potential_prompt_injection\", {\n        timestamp: new Date().toISOString(),\n        pattern: pattern.source,\n        data_preview: cleaned.substring(0, 200)\n      });\n      \/\/ Escape thay vì loại bỏ để giữ nguyên nội dung hiển thị\n      cleaned = cleaned.replace(pattern, (match) =\u0026gt;\n        \"[FILTERED: \" + match.length + \" chars]\"\n      );\n    }\n  }\n\n  return cleaned;\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch3\u003eNguyên tắc defense in depth\u003c\/h3\u003e\n\u003cul\u003e\n  \u003cli\u003eKhông tin tưởng dữ liệu từ bất kỳ nguồn nào — kể cả database nội bộ\u003c\/li\u003e\n  \u003cli\u003eĐặt giới hạn kích thước output từ tool (ví dụ: tối đa 50KB)\u003c\/li\u003e\n  \u003cli\u003ePhân tách quyền: tool đọc dữ liệu không có quyền thực thi hành động nguy hiểm\u003c\/li\u003e\n  \u003cli\u003eHuman-in-the-loop: Yêu cầu người dùng xác nhận trước khi Agent thực hiện thao tác nhạy cảm (gửi email, xóa dữ liệu, chuyển tiền)\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch2\u003eTriển khai MCP Server trong container\u003c\/h2\u003e\n\u003cp\u003eChạy MCP Server trong Docker container giúp cô lập và kiểm soát tốt hơn:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003e# Dockerfile cho MCP Server\nFROM node:20-slim\n\n# Chạy với non-root user\nRUN groupadd -r mcp \u0026amp;\u0026amp; useradd -r -g mcp mcp\n\nWORKDIR \/app\nCOPY package*.json .\/\nRUN npm ci --only=production\n\nCOPY . .\nRUN chown -R mcp:mcp \/app\n\nUSER mcp\n\n# Không expose port nếu dùng stdio transport\n# EXPOSE 8443\n\nCMD [\"node\", \"server.js\"]\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003cpre\u003e\u003ccode\u003e# docker-compose.yml\nversion: \"3.8\"\nservices:\n  mcp-server:\n    build: .\n    restart: unless-stopped\n    environment:\n      - DB_HOST=db\n      - DB_PORT=5432\n      - DB_NAME=mydb\n      - DB_USER=mcp_readonly\n      - DB_PASSWORD_FILE=\/run\/secrets\/db_password\n    secrets:\n      - db_password\n    networks:\n      - mcp-network\n    deploy:\n      resources:\n        limits:\n          memory: 256M\n          cpus: \"0.5\"\n\nsecrets:\n  db_password:\n    file: .\/secrets\/db_password.txt\n\nnetworks:\n  mcp-network:\n    driver: bridge\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eKiểm tra bảo mật định kỳ\u003c\/h2\u003e\n\u003cp\u003eNgoài cấu hình ban đầu, cần thực hiện kiểm tra bảo mật định kỳ:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003eChecklist kiểm tra bảo mật MCP Server hàng tháng:\n\n1. Review audit logs: có pattern bất thường không?\n   - Query đến bảng\/cột nhạy cảm\n   - Số lượng request tăng đột biến\n   - Lỗi xác thực liên tiếp từ cùng IP\n2. Kiểm tra dependencies: npm audit, cập nhật bản vá bảo mật\n3. Rotate API keys và review danh sách client được phép\n4. Kiểm tra certificate TLS còn hạn (tự động với certbot)\n5. Review và cập nhật danh sách SENSITIVE_COLUMNS\n   và BLOCKED_TABLES khi schema thay đổi\n6. Test thử tấn công: prompt injection, path traversal,\n   SQL injection qua tham số tool\n7. Backup audit logs và verify khả năng restore\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước tiếp theo\u003c\/h2\u003e\n\u003cp\u003eBảo mật MCP Server là quá trình liên tục, không phải cấu hình một lần. Hãy bắt đầu với các biện pháp cơ bản (read-only user, input validation, audit logging), sau đó nâng cấp dần lên OAuth 2.1, role-based access control và monitoring tự động. Khi triển khai cho tổ chức lớn, cân nhắc xây dựng MCP Gateway tập trung để quản lý nhiều MCP Server từ một điểm. Tham khảo thêm tại \u003ca href=\"\/en\/collections\/nang-cao\"\u003eThư viện Nâng cao Claude\u003c\/a\u003e.\u003c\/p\u003e\n","brand":"Minh Tuấn","offers":[{"title":"Default Title","offer_id":47730161221844,"sku":null,"price":0.0,"currency_code":"VND","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0821\/0264\/9044\/files\/b_o-m_t-mcp-server-authentication-authorization-va-best-practices.jpg?v=1774716148","url":"https:\/\/claude.vn\/en\/products\/b%e1%ba%a3o-m%e1%ba%adt-mcp-server-authentication-authorization-va-best-practices","provider":"CLAUDE.VN","version":"1.0","type":"link"}