Dữ liệu FDE TimesViệc làm FDE đang mở 824▼37 Thay đổi số việc đang mở trong 7 ngày, so sánh cùng phạm vi: không tính việc của các công ty mới được theo dõi tuần nàyMới trong 7 ngày 76Công ty đang tuyển 153Nhận làm từ xa 25%Lương trung vị (Mỹ) $202kTuyển nhiều nhất Databricks 104
中文EN

Tờ báo của nghề Forward Deployed Engineer

Bách khoa

Tool tải URL của agent là một proxy vào mạng nội bộ của khách

Deny-list không cứu được bạn; chỉ đường fetch ghim IP và đi qua egress proxy mới chặn được.

Chia sẻLinkedInFacebookX

Tóm tắt nhanh

  • Agent có tool tải URL mà chạy trong mạng khách thì ai điều khiển được prompt cũng có thể với tới dịch vụ nội bộ và metadata service.
  • Deny-list và tự viết code kiểm IP đều dễ bị qua mặt; nên dùng allow-list, ghim DNS, kiểm từng redirect và có egress proxy.
  • Trên AWS, hop limit mặc định 1 chặn container lấy token IMDSv2; ai nâng lên 2 là đã mở đường cho sandbox chạm tới credential.
Sơ đồ ba lớp xếp chồng để chặn SSRF cho agent. Trên cùng: lớp trong code, gồm allow-list và kiểm IP, là lớp lọc sớm. Ở giữa, tô màu cam đậm: egress proxy phân giải tên miền, kiểm IP và ghim kết nối, là lớp phòng thủ chính. Dưới cùng: mạng và metadata, gồm subnet riêng, IMDSv2 và hop limit.
Ba lớp nên vẽ khi trình bày với đội bảo mật của khách: lớp kiểm tra trong code chỉ giữ được khi mọi request đều đi qua nó. Egress proxy đóng khoảng hở giữa lúc kiểm và lúc kết nối ở cùng một chỗ. Nguồn: tài liệu security best practices của Model Context Protocol, OWASP, tài liệu AWS về IMDSv2.

Thử hình dung tuần thứ ba của bạn ở một khách hàng. Agent hỗ trợ nội bộ đã chạy ổn, và người dùng xin thêm một tính năng nhỏ: “dán link vào, agent đọc rồi tóm tắt”. Bạn thêm một tool fetch_url mất chừng hai mươi dòng code, demo trơn tru, và ai cũng vui.

Agent đó lại chạy trên một máy ảo trong VPC của khách. Máy ấy nhìn thấy wiki nội bộ, dashboard quản trị, cơ sở dữ liệu và dịch vụ metadata của cloud.

Giờ thì ai gõ được vào ô chat, hoặc cài được một câu lệnh vào trang web mà agent sẽ đọc, cũng có thể gửi request từ bên trong firewall. Tool hai mươi dòng kia đã trao cho họ quyền đó.

Lỗi này có tên là SSRF. FDE gần như chắc chắn sẽ gặp lỗi này, vì việc của bạn là đưa agent vào sát dữ liệu thật của khách. Phần dưới lần lượt xem lỗi xảy ra thế nào, một đường fetch an toàn trông ra sao, và những sai lầm hay gặp nhất.

Vì sao agent làm SSRF tệ hơn?

Ở ứng dụng web truyền thống, kẻ tấn công phải tìm ra một tham số URL bị lộ. Với agent, URL được chọn bởi một mô hình ngôn ngữ, và mô hình đó làm theo chữ, kể cả chữ do người khác cài vào.

Tài liệu security best practices của Model Context Protocol mô tả đúng kịch bản này. Trong danh sách hậu quả có một dòng FDE nên thuộc lòng: MCP client chạy phía server trở thành proxy, đi vòng qua các lớp kiểm soát ở biên mạng.

Chuyện này đã xảy ra ngoài đời. Một bản tin bảo mật tháng 5/2026 của CraftedSignal về gói auth-fetch-mcp cho thấy lỗ hổng SSRF trong tool fetch này cho phép ép server tải tài nguyên nội bộ, endpoint metadata của cloud hoặc địa chỉ loopback.

Mục tiêu đắt giá nhất nằm ngay trên máy

Trên cloud, máy chạy agent thường mang một IAM role. Ai lấy được token phiên IMDSv2 có thể dùng nó để đọc credential tạm thời của role đó từ metadata service. Khi ấy họ không cần đi qua agent nữa: họ cầm quyền của máy và gọi thẳng API của khách.

AWS thiết kế IMDSv2 để thêm một lớp phòng thủ cho những trường hợp firewall bị mở toang, reverse proxy cấu hình sai hay ứng dụng dính lỗ hổng SSRF. Cơ chế then chốt: phản hồi chứa token bị giảm TTL về 0 trước khi rời instance, nên chỉ chính instance mới nhận được token. Theo tài liệu AWS, hop limit mặc định của phản hồi này là 1.

Khi agent chạy trong container hay sandbox trên instance, con số này quyết định sandbox có lấy được token hay không. AWS giải thích rằng đi vào container được tính thêm một hop, nên với hop limit 1, container có thể không nhận được phản hồi nào.

Hệ quả là: mặc định 1 chặn container cách instance một hop lấy token, còn nâng lên 2, như chính AWS gợi ý cho môi trường container, là cho sandbox chạm tới credential của máy.

Nếu ai đó đã nâng hop limit “cho chạy được”, bạn cần biết lý do. AWS cũng nêu một lối khác: truyền thẳng các thiết lập như Region vào container thay vì mở metadata cho nó.

Một đường fetch an toàn trông thế nào

Câu hỏi đầu tiên với khách luôn là: agent có thật sự cần đọc mọi URL không? Nếu người dùng chỉ dán link Confluence và GitHub của công ty, hãy dùng allow-list. Nhưng allow-list theo tên miền một mình không chặn được DNS rebinding.

Lý do nằm ở khoảng hở thời gian mà tài liệu MCP gọi là TOCTOU của DNS. Lúc bạn kiểm tra, tên miền trỏ về một IP công khai; đến lúc kết nối, thư viện HTTP có thể phân giải lại và nhận về một IP nội bộ.

OWASP cảnh báo một lần phân giải thứ hai không được kiểm tra, xen giữa lúc xác thực và lúc kết nối, có thể vượt qua các bước kiểm tra đó.

Advisory về MCP Atlassian năm 2026 là ví dụ thật: sau bước xác thực, requests.get phân giải DNS lần hai và nhận về 169.254.169.254, địa chỉ metadata. Cách sửa mà MCP gợi ý là ghim kết quả phân giải: phân giải một lần, kiểm IP đó, rồi kết nối đúng IP đó.

Dưới đây là phần lõi của bước kiểm tra, viết bằng Python:

import ipaddress, socket
from urllib.parse import urlparse

class BlockedDestination(Exception):
    pass

def resolve_and_check(url: str):
    parsed = urlparse(url)
    if parsed.scheme not in ("http", "https"):
        raise BlockedDestination(f"scheme {parsed.scheme}")
    host = parsed.hostname
    ips = {ipaddress.ip_address(info[4][0])
           for info in socket.getaddrinfo(host, None)}
    for ip in ips:
        if ip.version == 6 and ip.ipv4_mapped:
            ip = ip.ipv4_mapped
        if (ip.is_private or ip.is_loopback or ip.is_link_local
                or ip.is_reserved or ip.is_multicast or ip.is_unspecified):
            raise BlockedDestination(f"{host} -> {ip}")
    return host, sorted(ips, key=str)[0]  # IP sẽ ghim để kết nối

Có ba chi tiết đáng chú ý. Hàm dùng thư viện chuẩn chứ không tự cắt chuỗi IP, vì tài liệu MCP cảnh báo kẻ tấn công lách parser tự viết bằng cách viết IP dạng bát phân, thập lục phân hay IPv4-mapped IPv6.

Hàm từ chối nếu bất kỳ IP nào của tên miền nằm trong dải private, loopback hay link-local. Và nó trả về IP để bước sau kết nối thẳng vào đó, không phân giải lại.

Phần khó nằm ở chính bước “kết nối thẳng vào IP” khi URL là HTTPS. Bạn mở socket tới IP đã ghim, nhưng SNI trong bắt tay TLS, việc kiểm chứng chỉ và header Host vẫn phải mang tên miền gốc, nếu không server sẽ trả sai trang hoặc chứng chỉ bị từ chối.

OWASP lưu ý không phải SDK nào cũng có sẵn cơ chế kiểm tra kiểu này, nên lập trình viên phải tự lo các trường hợp biên.

Advisory về datamodel-code-generator cho thấy giá của việc đó: guard kiểm IP một lần rồi để httpx tự phân giải DNS, nên không gì ràng buộc kết nối vào IP đã qua kiểm tra.

Vì thế, hãy coi hàm trên là lớp lọc sớm trong ứng dụng, còn việc ghim IP thì nên giao cho egress proxy ở phần dưới.

Bước sau là vòng lặp redirect. Hãy tắt chế độ tự theo redirect của thư viện HTTP, chẳng hạn allow_redirects=False. Mỗi lần nhận mã 3xx, lấy header Location, gọi lại resolve_and_check và dừng sau vài bước nhảy, vì URL đầu tiên có thể sạch còn URL thứ ba mới trỏ vào trong.

Code tốt vẫn chưa phải lớp phòng thủ chính

Hàm trên là lớp bảo vệ trong ứng dụng. Nó chỉ giữ được nếu mọi đường gửi request đều đi qua nó, kể cả browser tool, MCP server bên thứ ba và webhook. Chỉ một đường quên gọi là đủ để thủng.

Vì thế tài liệu MCP khuyên các deployment phía server dùng egress proxy như Smokescreen, loại proxy ngăn SSRF ngay từ thiết kế, thay vì tự vá từng adapter. Chính proxy phân giải tên miền, kiểm IP và mở kết nối, nên khoảng hở giữa lúc kiểm và lúc dùng được đóng ở một chỗ, thay vì rải trong từng tool.

Ở chỗ khách, cách làm hợp lý là đặt agent vào một subnet chỉ có đường ra internet qua proxy, không có route tới cơ sở dữ liệu, bắt buộc IMDSv2 và giữ hop limit ở mức không cho sandbox với tới token.

Khi trình bày với đội bảo mật của khách, hãy vẽ ba lớp: allow-list và kiểm IP trong code, egress proxy ở giữa, phân đoạn mạng cùng cấu hình metadata ở dưới cùng. Một lớp có hỏng thì vẫn còn các lớp còn lại chặn. Một sơ đồ như vậy thường giúp bạn qua security review nhanh hơn nhiều so với một câu “chúng tôi đã validate URL”.

Những sai lầm hay gặp

Sai lầm phổ biến nhất là viết deny-list kiểu “chặn chuỗi localhost và 127.”. Chuỗi đó có nhiều cách viết khác nhau, và đó chính là kiểu kiểm tra tự viết mà tài liệu MCP bảo nên tránh. Sai lầm thứ hai là kiểm URL một lần ở đầu rồi để thư viện HTTP tự theo redirect và tự phân giải DNS lại.

Sai lầm thứ ba là chỉ nghĩ tới người dùng gõ URL độc. Với agent, URL có thể nằm trong một email, một ticket hay một trang web mà agent được nhờ đọc. Sai lầm thứ tư là tin rằng cloud đã lo phần metadata, trong khi một thay đổi hop limit “cho container chạy được” có thể mở lại đúng cánh cửa đó.

Một sơ đồ vừa để sửa lỗi, vừa để xin việc

Bài tập cho tuần này: lấy sơ đồ mạng của deployment gần nhất bạn làm, đánh dấu máy chạy agent, rồi vẽ mọi mũi tên mà máy đó gửi được request tới. Mũi tên nào bạn không giải thích được với khách thì đó là việc cần làm trước demo kế tiếp.

Bản sơ đồ ấy, cùng danh sách những mũi tên bạn đã cắt, cũng là bằng chứng tốt nhất khi đi xin việc. Nếu một tin tuyển dụng nhắc tới việc triển khai trong hạ tầng của khách hay làm việc với đội bảo mật, hãy kể đúng câu chuyện đó trong phỏng vấn: máy nào, mũi tên nào, chặn bằng lớp nào.

Trong CV, một dòng như “thiết kế egress policy và chặn SSRF cho agent chạy trong mạng khách hàng, qua được security review” nói lên nhiều điều hơn ba dòng liệt kê framework. Người tuyển FDE cần biết bạn nhìn thấy những mũi tên mà người khác bỏ sót.

Bài này có hữu ích không?

Dùng cùng trợ lý AIHỏi Claude ↗Hỏi ChatGPT ↗
8 nguồn
Đọc tiếp trên lộ trình · Chặng 3: AI ứng dụngMCP server bạn đã duyệt hôm qua có thể đổi mặt sau một bản cập nhậtCách đọc, ghim phiên bản và cách ly server bên thứ ba trước khi agent chạm vào dữ liệu của khách.