Bảo vệ tài nguyên của bạn khỏi các cuộc tấn công web bằng công cụ Tìm nạp siêu dữ liệu

Ngăn chặn rò rỉ thông tin về CSRF, XSSI và nhiều nguồn gốc.

Lukas Weichselbaum
Lukas Weichselbaum

Tại sao bạn nên quan tâm đến việc cách ly các tài nguyên trên web?

Nhiều ứng dụng web dễ bị tấn công nhiều nguồn gốc như giả mạo yêu cầu trên nhiều trang web (CSRF), đưa tập lệnh vào nhiều trang web (XSSI), tấn công xác định thời gian, rò rỉ thông tin nhiều nguồn gốc hoặc tấn công kênh bên thực thi suy đoán (Spectre).

Các tiêu đề của yêu cầu Tìm nạp siêu dữ liệu cho phép bạn triển khai một cơ chế bảo vệ chuyên sâu mạnh mẽ – Chính sách tách biệt tài nguyên – để bảo vệ ứng dụng của bạn khỏi các cuộc tấn công nhiều nguồn gốc phổ biến này.

Thông thường, các tài nguyên mà một ứng dụng web nhất định hiển thị là chỉ được tải bởi chính ứng dụng đó chứ không phải các trang web khác. Trong những trường hợp như vậy, việc triển khai Chính sách tách biệt tài nguyên dựa trên các tiêu đề của yêu cầu Siêu dữ liệu tìm nạp không mất nhiều công sức, đồng thời bảo vệ ứng dụng khỏi các cuộc tấn công trên nhiều trang web.

Khả năng tương thích với trình duyệt

Tất cả công cụ trình duyệt hiện đại đều hỗ trợ tiêu đề của yêu cầu Tìm nạp siêu dữ liệu.

Hỗ trợ trình duyệt

  • 76
  • 79
  • 90
  • 16,4

Nguồn

Thông tin khái quát

Nhiều cuộc tấn công trên nhiều trang web có thể xảy ra do web mở theo mặc định và máy chủ ứng dụng của bạn không thể dễ dàng tự bảo vệ mình khỏi hoạt động giao tiếp bắt nguồn từ các ứng dụng bên ngoài. Tấn công nhiều nguồn gốc điển hình là hành vi giả mạo yêu cầu trên nhiều trang web (CSRF), trong đó kẻ tấn công dụ người dùng truy cập vào trang web mà chúng kiểm soát rồi gửi biểu mẫu đến máy chủ mà người dùng đã đăng nhập. Vì máy chủ không thể biết liệu yêu cầu có bắt nguồn từ một miền khác (cross-site) hay không và trình duyệt tự động đính kèm cookie vào yêu cầu trên nhiều trang web, nên máy chủ sẽ thay mặt người dùng thực thi hành động do kẻ tấn công yêu cầu.

Các cuộc tấn công trên nhiều trang web khác như tập lệnh trên nhiều trang web (XSSI) hoặc rò rỉ thông tin trên nhiều nguồn gốc cũng tương tự như CSRF và dựa vào việc tải tài nguyên từ ứng dụng bị tấn công trong tài liệu do kẻ tấn công kiểm soát cũng như làm rò rỉ thông tin về ứng dụng của nạn nhân. Vì không thể dễ dàng phân biệt yêu cầu đáng tin cậy với yêu cầu không đáng tin cậy, nên ứng dụng không thể loại bỏ lưu lượng truy cập độc hại trên nhiều trang web.

Ra mắt tính năng Tìm nạp siêu dữ liệu

Tiêu đề của yêu cầu tìm nạp siêu dữ liệu là một tính năng bảo mật mới của nền tảng web, được thiết kế nhằm giúp máy chủ tự bảo vệ khỏi các cuộc tấn công trên nhiều nguồn gốc. Bằng cách cung cấp thông tin về ngữ cảnh của một yêu cầu HTTP trong một nhóm tiêu đề Sec-Fetch-*, các mô-đun này cho phép máy chủ phản hồi áp dụng các chính sách bảo mật trước khi xử lý yêu cầu. Điều này cho phép nhà phát triển quyết định sẽ chấp nhận hay từ chối một yêu cầu dựa trên cách thức đưa ra và bối cảnh sử dụng yêu cầu đó, nhờ đó, nhà phát triển chỉ có thể phản hồi các yêu cầu hợp lệ do ứng dụng của họ đưa ra.

Cùng nguồn gốc
Các yêu cầu bắt nguồn từ những trang web do máy chủ của riêng bạn (cùng nguồn gốc) phân phát sẽ tiếp tục hoạt động. Yêu cầu tìm nạp từ https://site.example cho tài nguyên https://site.example/foo.json trong JavaScript khiến trình duyệt gửi tiêu đề yêu cầu HTTP "Sec Fetch-Site: same-origin".
Trên nhiều trang web
Các yêu cầu độc hại trên nhiều trang web có thể bị máy chủ từ chối vì ngữ cảnh bổ sung trong yêu cầu HTTP do các tiêu đề Sec-Fetch-* cung cấp. Một hình ảnh trên https://evil.example đã đặt thuộc tính src của một phần tử img thành "https://site.example/foo.json" khiến trình duyệt gửi tiêu đề của yêu cầu HTTP "Sec-Fetch-Site: cross-site".

Sec-Fetch-Site

Hỗ trợ trình duyệt

  • 76
  • 79
  • 90
  • 16,4

Nguồn

Sec-Fetch-Site cho máy chủ biết trang web nào đã gửi yêu cầu. Trình duyệt đặt giá trị này thành một trong các giá trị sau:

  • same-origin, nếu yêu cầu là do chính ứng dụng của bạn đưa ra (ví dụ: site.example)
  • same-site, nếu yêu cầu được thực hiện từ một miền con của trang web (ví dụ: bar.site.example)
  • none, nếu yêu cầu là do hoạt động tương tác của người dùng với tác nhân người dùng một cách rõ ràng (ví dụ: nhấp vào một dấu trang) gây ra
  • cross-site, nếu yêu cầu được gửi bởi một trang web khác (ví dụ: evil.example)

Sec-Fetch-Mode

Hỗ trợ trình duyệt

  • 76
  • 79
  • 90
  • 16,4

Nguồn

Sec-Fetch-Mode cho biết chế độ của yêu cầu. Điều này tương ứng với loại yêu cầu và cho phép bạn phân biệt tải tài nguyên với các yêu cầu điều hướng. Ví dụ: đích đến là navigate biểu thị yêu cầu điều hướng cấp cao nhất trong khi no-cors biểu thị các yêu cầu về tài nguyên như tải một hình ảnh.

Sec-Fetch-Dest

Hỗ trợ trình duyệt

  • 80
  • 80
  • 90
  • 16,4

Nguồn

Sec-Fetch-Dest hiển thị đích đến của một yêu cầu (ví dụ: nếu thẻ script hoặc img khiến trình duyệt yêu cầu tài nguyên).

Cách sử dụng tính năng Siêu dữ liệu tìm nạp để chống lại các cuộc tấn công trên nhiều nguồn gốc

Thông tin bổ sung mà các tiêu đề yêu cầu này cung cấp khá đơn giản, nhưng ngữ cảnh bổ sung cho phép bạn xây dựng logic bảo mật mạnh mẽ ở phía máy chủ (còn được gọi là Chính sách cách ly tài nguyên) chỉ với một vài dòng mã.

Triển khai chính sách tách biệt tài nguyên

Chính sách cách ly tài nguyên ngăn các trang web bên ngoài yêu cầu tài nguyên của bạn. Việc chặn lưu lượng truy cập như vậy giúp giảm thiểu các lỗ hổng bảo mật phổ biến trên web trên nhiều trang web (chẳng hạn như CSRF, XSSI), tấn công theo thời gian và rò rỉ thông tin trên nhiều nguồn gốc. Bạn có thể bật chính sách này cho mọi điểm cuối của ứng dụng và cho phép tất cả các yêu cầu về tài nguyên đến từ ứng dụng của bạn cũng như các thao tác điều hướng trực tiếp (thông qua một yêu cầu HTTP GET). Bạn có thể chọn không sử dụng logic này cho các điểm cuối dự kiến được tải trong ngữ cảnh nhiều trang web (ví dụ: các điểm cuối được tải bằng CORS).

Bước 1: Cho phép yêu cầu từ các trình duyệt không gửi siêu dữ liệu Tìm nạp

Vì không phải trình duyệt nào cũng hỗ trợ Siêu dữ liệu tìm nạp, nên bạn cần cho phép các yêu cầu không đặt tiêu đề Sec-Fetch-* bằng cách kiểm tra sự hiện diện của sec-fetch-site.

if not req['sec-fetch-site']:
  return True  # Allow this request

Bước 2: Cho phép các yêu cầu do cùng một trang web và trình duyệt khởi tạo

Mọi yêu cầu không xuất phát từ một ngữ cảnh nhiều nguồn gốc (như evil.example) đều sẽ được cho phép. Cụ thể, đây là những yêu cầu:

  • Bắt nguồn từ ứng dụng của riêng bạn (ví dụ: yêu cầu cùng nguồn gốc mà trong đó site.example các yêu cầu site.example/foo.json sẽ luôn được cho phép).
  • Bắt nguồn từ miền con của bạn.
  • Nguyên nhân rõ ràng là do hoạt động tương tác của người dùng với tác nhân người dùng (ví dụ: điều hướng trực tiếp hoặc bằng cách nhấp vào dấu trang, v.v.).
if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
  return True  # Allow this request

Bước 3: Cho phép điều hướng ở cấp cao nhất đơn giản và lấy khung hình

Để đảm bảo rằng trang web của bạn vẫn có thể liên kết được từ các trang web khác, bạn phải cho phép (HTTP GET) thao tác đơn giản ở cấp cao nhất.

if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
  # <object> and <embed> send navigation requests, which we disallow.
  and req['sec-fetch-dest'] not in ('object', 'embed'):
    return True  # Allow this request

Bước 4: Chọn không tham gia những điểm cuối dành để phân phát lưu lượng truy cập trên nhiều trang web (Không bắt buộc)

Trong một số trường hợp, ứng dụng của bạn có thể cung cấp tài nguyên để tải trên nhiều trang web. Những tài nguyên này cần được loại trừ trên mỗi đường dẫn hoặc mỗi điểm cuối. Ví dụ về các điểm cuối như vậy:

  • Điểm cuối được truy cập trên nhiều nguồn gốc: Nếu ứng dụng của bạn đang phân phát điểm cuối được bật CORS, bạn cần chọn không sử dụng tính năng tách biệt tài nguyên một cách rõ ràng để đảm bảo vẫn có thể gửi yêu cầu trên nhiều trang web đến những điểm cuối này.
  • Tài nguyên công khai (ví dụ: hình ảnh, kiểu, v.v.): Mọi tài nguyên công khai và chưa được xác thực mà có thể tải trên nhiều nguồn gốc từ các trang web khác cũng có thể được miễn trừ.
if req.path in ('/my_CORS_endpoint', '/favicon.png'):
  return True

Bước 5: Từ chối tất cả các yêu cầu khác liên quan đến nhiều trang web và không phải là yêu cầu điều hướng

Chính sách cách ly tài nguyên này sẽ từ chối mọi yêu cầu trên nhiều trang web khác, qua đó bảo vệ ứng dụng của bạn khỏi các cuộc tấn công phổ biến trên nhiều trang web.

Ví dụ: Mã sau đây minh hoạ cách triển khai đầy đủ một Chính sách cách ly tài nguyên mạnh mẽ trên máy chủ hoặc làm phần mềm trung gian để từ chối các yêu cầu tài nguyên độc hại trên nhiều trang web, trong khi vẫn cho phép các yêu cầu điều hướng đơn giản:

# Reject cross-origin requests to protect from CSRF, XSSI, and other bugs
def allow_request(req):
  # Allow requests from browsers which don't send Fetch Metadata
  if not req['sec-fetch-site']:
    return True

  # Allow same-site and browser-initiated requests
  if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
    return True

  # Allow simple top-level navigations except <object> and <embed>
  if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
    and req['sec-fetch-dest'] not in ('object', 'embed'):
      return True

  # [OPTIONAL] Exempt paths/endpoints meant to be served cross-origin.
  if req.path in ('/my_CORS_endpoint', '/favicon.png'):
    return True

  # Reject all other requests that are cross-site and not navigational
  return False

Triển khai chính sách tách biệt tài nguyên

  1. Cài đặt một mô-đun như đoạn mã ở trên để ghi nhật ký và theo dõi cách hoạt động của trang web, đồng thời đảm bảo các hạn chế đó không ảnh hưởng đến bất kỳ lưu lượng truy cập hợp lệ nào.
  2. Khắc phục các lỗi vi phạm tiềm ẩn bằng cách miễn trừ các điểm cuối hợp lệ trên nhiều nguồn gốc.
  3. Thực thi chính sách bằng cách bỏ qua các yêu cầu không tuân thủ.

Xác định và khắc phục các lỗi vi phạm chính sách

Bạn nên thử nghiệm chính sách của mình theo cách không có tác dụng phụ, trước tiên, hãy bật chính sách này ở chế độ báo cáo trong mã phía máy chủ của bạn. Ngoài ra, bạn có thể triển khai logic này trong phần mềm trung gian hoặc trong một proxy ngược để ghi lại mọi lỗi vi phạm mà chính sách của bạn có thể tạo ra khi áp dụng cho lưu lượng truy cập chính thức.

Từ kinh nghiệm triển khai Chính sách tách biệt tài nguyên siêu dữ liệu tìm nạp tại Google, hầu hết các ứng dụng đều tương thích với chính sách này theo mặc định và hiếm khi yêu cầu miễn trừ các điểm cuối để cho phép lưu lượng truy cập trên nhiều trang web.

Thực thi chính sách tách biệt tài nguyên

Sau khi kiểm tra để đảm bảo rằng chính sách của mình không ảnh hưởng đến lưu lượng truy cập hợp lệ trên kênh phát hành công khai, bạn đã sẵn sàng thực thi các quy định hạn chế, đảm bảo rằng các trang web khác sẽ không thể yêu cầu tài nguyên của bạn và bảo vệ người dùng khỏi các cuộc tấn công trên nhiều trang web.

Tài liệu đọc thêm