Lập trình · 02/10/2026

Fetch Metadata thực chiến: Dùng Sec-Fetch-* chặn request cross-site

Một request có cookie hợp lệ chưa chắc xuất phát từ giao diện của bạn. Trình duyệt có thể gửi request từ form, ảnh, iframe hoặc script trên website khác và tự đính kèm credential theo chính sách cookie. Fetch Metadata bổ sung các header Sec-Fetch-* để server biết request được tạo trong ngữ cảnh nào trước khi chạy logic nghiệp vụ.

Fetch Metadata thực chiến: Dùng Sec-Fetch-* chặn request cross-site

Một request có cookie hợp lệ chưa chắc xuất phát từ giao diện của bạn. Trình duyệt có thể gửi request từ form, ảnh, iframe hoặc script trên website khác và tự đính kèm credential theo chính sách cookie. Fetch Metadata bổ sung các header Sec-Fetch-* để server biết request được tạo trong ngữ cảnh nào trước khi chạy logic nghiệp vụ.

Bằng một Resource Isolation Policy nhỏ ở middleware hoặc reverse proxy, ứng dụng có thể từ chối nhiều request cross-site không hợp lệ từ sớm. Đây là lớp phòng thủ bổ sung cho CSRF, XSSI và rò rỉ cross-origin; nó không thay thế CSRF token, SameSite cookie, CORS, xác thực hay phân quyền.

1. Fetch Metadata trả lời những câu hỏi nào?

Đặc tả Fetch Metadata Request Headers của W3C định nghĩa các tín hiệu do user agent gửi để server quyết định có phục vụ request hay không:

HeaderCâu hỏiGiá trị thường gặp
Sec-Fetch-SiteQuan hệ giữa initiator và đích?same-origin, same-site, cross-site, none
Sec-Fetch-ModeRequest chạy ở mode nào?navigate, cors, no-cors, same-origin, websocket
Sec-Fetch-DestTài nguyên sẽ được dùng làm gì?document, image, script, style, empty…
Sec-Fetch-UserNavigation có user activation??1 khi có tín hiệu phù hợp

Các tên bắt đầu bằng Sec- thuộc nhóm header mà JavaScript phía trang không được tùy ý sửa. Vì vậy một website tấn công không thể đơn giản gọi fetch() rồi tự gắn Sec-Fetch-Site: same-origin. Tuy nhiên, client ngoài trình duyệt vẫn có thể tự tạo header; Fetch Metadata không phải cơ chế chứng thực client.

2. same-origin, same-site và none không đồng nghĩa

  • same-origin: scheme, host và port của initiator khớp với đích. Đây thường là tín hiệu mạnh nhất cho request nội bộ.
  • same-site: khác origin nhưng vẫn cùng site theo quy tắc của trình duyệt, chẳng hạn một số subdomain cùng registrable domain.
  • cross-site: request bắt nguồn từ site khác.
  • none: navigation được user agent coi là do người dùng trực tiếp khởi tạo, như nhập URL hoặc mở bookmark.

Đừng mặc định coi mọi subdomain là đáng tin. Nếu người dùng có thể tạo nội dung ở tenant.example.com, nếu subdomain trỏ tới dịch vụ SaaS hoặc có nguy cơ takeover, cho phép toàn bộ same-site có thể mở lại đường tấn công. Với endpoint nhạy cảm, chính sách nên ưu tiên same-origin và chỉ thêm ngoại lệ có chủ đích.

3. Một Resource Isolation Policy tối thiểu

Chính sách phổ biến cho ứng dụng web hoạt động theo thứ tự:

  1. Cho phép request không có Fetch Metadata trong giai đoạn tương thích, nhưng đo lường chúng.
  2. Cho phép same-origin; cân nhắc same-site theo mô hình tin cậy subdomain.
  3. Cho phép navigation GET hợp lệ để liên kết từ website khác vẫn mở được trang.
  4. Miễn trừ chính xác các endpoint vốn phải nhận traffic cross-site.
  5. Từ chối các trường hợp cross-site còn lại trước khi chạy session và nghiệp vụ.
function allowByFetchMetadata(array $server, string $method, string $path): bool
{
    $site = strtolower($server['HTTP_SEC_FETCH_SITE'] ?? '');
    $mode = strtolower($server['HTTP_SEC_FETCH_MODE'] ?? '');
    $dest = strtolower($server['HTTP_SEC_FETCH_DEST'] ?? '');

    // Client cũ, app mobile, CLI và server-to-server có thể không gửi header.
    if ($site === '') {
        return true;
    }

    if ($site === 'same-origin') {
        return true;
    }

    // Chỉ bật nếu toàn bộ subdomain cùng site đều đáng tin.
    if ($site === 'same-site') {
        return true;
    }

    // Giữ khả năng mở link cross-site trong tab chính.
    if ($method === 'GET'
        && $mode === 'navigate'
        && !in_array($dest, ['object', 'embed'], true)) {
        return true;
    }

    return false;
}

Middleware thực tế nên kiểm tra một tập giá trị đã biết. Đặc tả khuyến nghị bỏ qua header có giá trị không hợp lệ để tương thích với mở rộng tương lai; không nên biến một token mới thành sự cố diện rộng. Cách fail-open hay fail-closed cho giá trị lạ phải dựa trên độ nhạy endpoint và dữ liệu quan sát được.

4. Đặt middleware đúng vị trí

Kiểm tra Fetch Metadata nên chạy càng sớm càng tốt: sau lớp chuẩn hóa host/TLS cần thiết nhưng trước session, xác thực nặng, truy vấn database và tác vụ có side effect. Request bị chặn thường trả 403 Forbidden với body nhỏ, không tiết lộ endpoint có tồn tại hay trạng thái tài khoản.

if (!allowByFetchMetadata($_SERVER, $_SERVER['REQUEST_METHOD'], $path)) {
    http_response_code(403);
    header('Content-Type: application/json; charset=utf-8');
    echo '{"error":"request_context_not_allowed"}';
    exit;
}

Ở kiến trúc nhiều dịch vụ, lớp edge có thể chặn phần lớn traffic, nhưng ứng dụng vẫn cần biết ngoại lệ nào thuộc route nào. Đừng dùng một regex đường dẫn rộng ở CDN rồi giả định mọi backend đều được bảo vệ. Policy nên nằm trong source control, có test và có owner.

5. Những endpoint cần ngoại lệ rõ ràng

Loại endpointVì sao khác biệt?Cách xử lý
API CORS công khaiĐược thiết kế để frontend origin khác gọiAllowlist route và origin; vẫn áp dụng CORS, auth, rate limit
WebhookServer bên thứ ba không gửi Fetch MetadataXác minh chữ ký, timestamp, replay và idempotency
OAuth/SAML callbackLuồng đăng nhập đi qua site ngoàiAllowlist callback; xác minh state, PKCE hoặc assertion
Ảnh/font nhúng công khaiCó chủ đích được tải cross-siteMiễn trừ tài nguyên tĩnh cụ thể; không để lẫn dữ liệu riêng tư
Payment return/callbackNavigation hoặc POST có thể đến từ cổng thanh toánThiết kế route riêng và xác minh giao dịch phía server

Ngoại lệ nên theo route hoặc capability, không theo chuỗi con mơ hồ. Ví dụ, miễn trừ /public/assets/ an toàn hơn miễn trừ mọi URL chứa từ “public”. Mỗi ngoại lệ cần lý do, test và ngày rà soát.

6. Vì sao không được bỏ CSRF token và SameSite?

Fetch Metadata chỉ xuất hiện ở user agent hỗ trợ và trong ngữ cảnh phù hợp. Mobile app, bot, CLI, WebView, proxy đặc biệt hoặc browser cũ có thể không gửi header. Nếu policy cho phép request thiếu header để giữ tương thích, kẻ tấn công ngoài browser cũng có thể gửi request thiếu header.

  • CSRF token chứng minh form/request có giá trị bí mật gắn với phiên hoặc hành động.
  • SameSite cookie kiểm soát lúc browser đính kèm cookie trong ngữ cảnh cross-site.
  • Origin/Referer validation cung cấp tín hiệu nguồn cho các request cần kiểm tra.
  • Fetch Metadata mô tả ngữ cảnh request để chặn sớm và bao phủ thêm nhiều kiểu resource load.

Các lớp này bổ sung nhau. CORS cũng không phải CSRF defense tổng quát: một cross-site form submission “simple request” có thể được gửi dù JavaScript phía tấn công không đọc được response.

7. Cache và header Vary

Nếu cùng một URL trả response khác nhau dựa trên Sec-Fetch-Site, Sec-Fetch-Mode hoặc Sec-Fetch-Dest, cache phải biết các biến thể đó. Đặc tả lưu ý dùng Vary thích hợp, chẳng hạn:

Vary: Accept-Encoding, Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest

Nếu không, một response 403 cho cross-site request có thể bị cache và phục vụ nhầm cho same-origin request, hoặc ngược lại. Tuy nhiên, thêm quá nhiều chiều Vary làm giảm hit ratio. Với endpoint động có credential, thường nên cấu hình cache riêng hoặc không shared-cache thay vì dựa vào một danh sách biến thể phức tạp.

8. Quan sát trước khi enforce

Fetch Metadata không có response header “Report-Only” chuẩn như CSP. Chế độ quan sát phải được xây trong middleware: tính quyết định dự kiến, ghi metric, nhưng vẫn cho request đi tiếp.

fetch_metadata_decision_total{
  decision="would_block",
  site="cross-site",
  route_group="account_write",
  method="POST"
}

Không đưa URL đầy đủ, cookie, query chứa token hay dữ liệu cá nhân vào nhãn metric. Nhãn có cardinality cao sẽ làm hệ thống quan sát tốn kém. Nên nhóm route theo capability và log có sampling với request ID.

Hướng dẫn triển khai Fetch Metadata của web.dev đề xuất bật logic ở chế độ chỉ ghi nhận, xử lý ngoại lệ hợp lệ rồi mới enforce. Một lộ trình an toàn:

  1. Quan sát 100% traffic trong ít nhất một chu kỳ sử dụng bình thường.
  2. Phân loại client thiếu header và các route nhận cross-site hợp lệ.
  3. Enforce trước cho endpoint ghi nhạy cảm có traffic trình duyệt rõ ràng.
  4. Mở rộng theo route group; giữ kill switch có thời hạn.
  5. Cảnh báo khi tỷ lệ block hoặc missing-header thay đổi đột ngột.

9. Bộ test phải bao phủ ngữ cảnh, không chỉ URL

Kịch bảnKỳ vọng
XHR/fetch same-origin tới APICho phép
POST form từ site tấn công tới endpoint ghiChặn trước nghiệp vụ
Ảnh cross-site trỏ vào JSON riêng tưChặn
Người dùng mở link GET từ site khácCho phép navigation phù hợp
Request từ client không có Fetch MetadataTheo policy tương thích đã công bố
OAuth callback/webhook được miễn trừĐi qua rồi được cơ chế chuyên biệt xác minh
Giá trị header mới hoặc không hợp lệKhông gây lỗi 500; hành vi đúng chiến lược tương thích

Test tích hợp nên chạy trong browser thật để browser tự sinh header. Unit test với header tự dựng chỉ kiểm tra middleware, không chứng minh hành vi end-to-end. Đồng thời thử redirect chain, vì Sec-Fetch-Site có thể chuyển thành cross-site khi chuỗi redirect đi qua site khác.

10. Checklist production

  • Đã xác định subdomain nào đáng tin; không mặc định cho phép same-site.
  • Đã lập danh sách hữu hạn cho CORS API, webhook, callback đăng nhập/thanh toán và tài nguyên nhúng.
  • Policy chạy trước xử lý tốn kém và side effect, trả lỗi nhỏ không rò thông tin.
  • CSRF token, SameSite, auth, authorization và rate limit vẫn được giữ nguyên.
  • Đã quyết định rõ cách xử lý request thiếu header và client ngoài browser.
  • Cache có Vary phù hợp hoặc endpoint không shared-cache.
  • Đã quan sát, canary, kiểm thử browser và chuẩn bị rollback có kiểm soát.

Fetch Metadata hiệu quả nhất khi được xem là một bộ tín hiệu để thu hẹp bề mặt request, không phải bằng chứng danh tính. Một policy nhỏ, route-aware và triển khai theo dữ liệu có thể chặn traffic cross-site vô nghĩa trước khi chạm vào ứng dụng, đồng thời giữ nguyên các lớp bảo vệ nền tảng cho những trường hợp header vắng mặt hoặc ngoại lệ hợp lệ.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.