Bảo mật MCP server từ xa: OAuth 2.1, CIMD và những lỗi chết người
Tóm tắt
MCP server qua Streamable HTTP là API công khai cho agent. Spec yêu cầu kiểm tra Origin, OAuth 2.1 với PKCE và tham số resource, chỉ nhận token cấp cho chính server và cấm chuyển tiếp token xuống API phía sau.
MCP server chạy bằng stdio trên máy bạn khá đơn giản: client khởi động server như một tiến trình con, credential lấy từ biến môi trường. Nhưng khi đưa server lên Internet cho cả team hay khách hàng dùng (transport Streamable HTTP), bạn đang vận hành một API công khai cho AI agent gọi vào. Spec MCP định nghĩa khá chặt cách xác thực bằng OAuth 2.1 và các yêu cầu bảo mật transport. Bỏ qua chúng là mở cửa cho rò rỉ token và tấn công "confused deputy".
Bảo mật transport: ba yêu cầu trước tiên
Spec cảnh báo rõ khi triển khai Streamable HTTP:
- Kiểm tra header
Originở mọi kết nối để chống tấn công DNS rebinding. - Chạy cục bộ thì bind vào
127.0.0.1, không bind0.0.0.0. - Xác thực mọi kết nối.
Thiếu các lớp này, một website độc hại có thể dùng DNS rebinding để gọi vào MCP server đang chạy trên máy bạn.
Ba vai trò trong luồng OAuth
| Vai trò | Trong MCP |
|---|---|
| Resource server | MCP server: nhận và kiểm tra access token |
| Client | MCP client (Claude, IDE, agent): xin token thay mặt người dùng |
| Authorization server | Nơi người dùng đăng nhập, đồng ý và cấp token (có thể là IdP sẵn có của công ty) |
Luồng xác thực từng bước
- Client gọi MCP server không có token → server trả 401 kèm header
WWW-Authenticatetrỏ tới metadata. - Client đọc Protected Resource Metadata (RFC 9728) tại
/.well-known/oauth-protected-resourceđể biết authorization server nào. - Client đọc metadata của authorization server (RFC 8414).
- Client đăng ký (xem bên dưới), tạo cặp PKCE, mở trình duyệt cho người dùng đăng nhập.
- Client đổi code lấy token, luôn kèm tham số
resource(RFC 8707) là URI chuẩn của MCP server. - Mọi request sau gửi
Authorization: Bearer …; không bao giờ đặt token trong query string.
Đăng ký client: CIMD thay cho DCR
Client và server MCP thường "chưa quen nhau" từ trước. Spec 2026-07-28 xếp thứ tự ưu tiên:
- Thông tin client đã đăng ký trước (nếu có).
- Client ID Metadata Documents (CIMD):
client_idchính là một URL HTTPS trỏ tới tệp JSON mô tả client (tên, redirect URI…). Authorization server tải về và kiểm tra. - Dynamic Client Registration (RFC 7591): nay đã bị deprecate, chỉ dùng để tương thích ngược.
- Cuối cùng mới nhờ người dùng nhập thông tin client.
{
"client_id": "https://app.example.com/oauth/client-metadata.json",
"client_name": "Example MCP Client",
"redirect_uris": ["http://127.0.0.1:3000/callback"],
"grant_types": ["authorization_code"],
"token_endpoint_auth_method": "none"
}
Những lỗi bảo mật chết người
| Lỗi | Hậu quả | Spec yêu cầu |
|---|---|---|
| Không kiểm tra audience của token | Token cấp cho dịch vụ khác cũng vào được server của bạn | Chỉ chấp nhận token cấp đích danh cho server này |
| Token passthrough: chuyển nguyên token của client xuống API phía sau | Confused deputy: API phía sau tin nhầm, vượt quyền | Cấm. Gọi API phía sau phải dùng token riêng do authorization server phía đó cấp |
| Redirect URI lỏng | Mã xác thực bị chuyển tới trang lừa đảo | So khớp chính xác redirect URI đã đăng ký; dùng tham số state |
| Token sống lâu, lưu không mã hoá | Lộ một lần là bị dùng mãi | Token ngắn hạn, xoay vòng refresh token cho public client |
Rủi ro và lưu ý
- Stdio không dùng luồng này: spec khuyên server stdio lấy credential từ môi trường. Đừng tự chế OAuth cho server chạy cục bộ.
- Đừng tự viết authorization server: dùng IdP có sẵn (Auth0, Keycloak, Entra ID, Cognito…) hỗ trợ các RFC nêu trên.
- OAuth chỉ chứng minh "ai": vẫn cần phân quyền từng tool (403 khi thiếu scope) và chống prompt injection ở tầng dữ liệu.
Áp dụng thế nào?
- Dev: Dùng phần auth có sẵn trong SDK MCP, kiểm tra audience ở middleware, test luồng đăng nhập bằng MCP Inspector trước khi phát hành.
- Tech Lead: Viết checklist review cho mọi MCP server từ xa: Origin, bind, audience, không passthrough, PKCE, redirect URI, thời hạn token.
- PM/Security: Xếp MCP server từ xa vào cùng quy trình đánh giá bảo mật như API công khai, kể cả khi "chỉ dùng nội bộ".
Nguồn & tham khảo
- Transports — Model Context Protocol
- Authorization — Model Context Protocol
- Client Registration (2026-07-28) — Model Context Protocol