HTTP Request Smuggling: Phá vỡ chuỗi liên kết giữa Proxy và Backend

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Khoảng cách vô hình trong kiến trúc Web hiện đại

Các ứng dụng web hiện đại hiếm khi hoạt động độc lập. Chúng thường nằm sau một hệ thống phức tạp gồm bộ cân bằng tải (load balancer), Tường lửa ứng dụng Web (WAF) và các reverse proxy như Nginx hoặc HAProxy. Mặc dù thiết lập này giúp tăng hiệu suất, nhưng it cũng tạo ra cơ hội nguy hiểm cho sự mất đồng bộ (desynchronization). Nếu các máy chủ này không thống nhất với nhau dù chỉ một byte về điểm kết thúc của một yêu cầu và điểm bắt đầu của yêu cầu tiếp theo, bạn sẽ gặp phải lỗ hổng HTTP Request Smuggling.

Gần đây, tôi đã kiểm thử một môi trường có lưu lượng truy cập cao, nơi WAF được cấu hình nghiêm ngặt để trả về mã lỗi 403 Forbidden cho bất kỳ truy cập nào vào đường dẫn /admin. Nhìn từ bên ngoài, thế trận bảo mật có vẻ rất vững chắc. Tuy nhiên, bằng cách khai thác cách máy chủ proxy front-end và máy chủ back-end diễn giải các header xung đột, tôi đã vượt qua bộ lọc hoàn toàn.

WAF nhìn thấy một yêu cầu 200 OK vô hại đến trang chủ, nhưng backend lại nhận được một lệnh bị “smuggled” (tuồn vào) đến bảng điều khiển admin. Đây không phải là một lỗi lập trình đơn giản. Đó là sự đổ vỡ cơ bản trong cách hai máy chủ khác nhau giao tiếp với nhau.

Nguyên nhân gốc rễ: Sự mơ hồ giữa CL và TE

HTTP/1.1 cung cấp hai cách để xác định độ dài thông điệp. Hầu hết chúng ta sử dụng Content-Length (CL), dùng để đếm kích thước thân (body) của yêu cầu bằng byte. Cách thay thế là Transfer-Encoding: chunked (TE), chia thông điệp thành các phần nhỏ hơn. Vấn đề bắt đầu khi kẻ tấn công gửi một yêu cầu chứa cả hai header này.

Nếu máy chủ front-end ưu tiên header CL nhưng back-end lại ưu tiên header TE, cách nhìn nhận của chúng về luồng dữ liệu sẽ khác nhau. Front-end chuyển tiếp một khối dữ liệu mà nó coi là một yêu cầu duy nhất. Tuy nhiên, back-end lại thấy điểm kết thúc của một thông điệp chunked ở giữa chừng và coi phần dữ liệu còn lại là điểm bắt đầu của một yêu cầu thứ hai, riêng biệt. Dữ liệu “thừa” này hiện đã được “smuggled” vào bộ đệm xử lý của máy chủ.

Ba biến thể chính

  • CL.TE: Front-end dựa vào Content-Length và back-end sử dụng Transfer-Encoding.
  • TE.CL: Front-end dựa vào Transfer-Encoding và back-end sử dụng Content-Length.
  • TE.TE: Cả hai máy chủ đều hỗ trợ Transfer-Encoding. Tuy nhiên, kẻ tấn công có thể ẩn header này khỏi một trong hai máy chủ bằng các biến thể như Transfer-Encoding: xchunked để buộc máy chủ đó phải quay lại sử dụng Content-Length.

Việc thắt chặt bảo mật máy chủ đòi hỏi nhiều hơn là chỉ sửa lỗi header; nó bắt đầu từ những thói quen cơ bản. Khi thiết lập môi trường production, tôi sử dụng trình tạo mật khẩu tại toolcraft.app/vi/tools/security/password-generator cho tất cả các tài khoản dịch vụ. Nó chạy cục bộ trong trình duyệt của bạn, vì vậy không có chuỗi nhạy cảm nào được truyền qua mạng. Tuy nhiên, ngay cả với thông tin đăng nhập mạnh, các lỗ hổng giao thức vẫn có thể cho phép kẻ tấn công “vượt rào” bằng cách đánh lừa chính cơ sở hạ tầng.

Thực hành: Khai thác CL.TE với Burp Suite

Để kiểm tra điều này, bạn cần một công cụ cho phép can thiệp trực tiếp vào HTTP header mà không bị “tự động sửa lỗi”. Burp Suite là tiêu chuẩn ngành cho việc này. Trong kịch bản CL.TE, mục tiêu là làm cho front-end nghĩ rằng yêu cầu rất dài, trong khi back-end lại nghĩ rằng nó kết thúc sớm.

Payload tấn công

Nếu chúng ta muốn truy cập vào endpoint /admin bị hạn chế, chúng ta có thể gửi payload cụ thể này tới front-end:

POST / HTTP/1.1
Host: vulnerable-site.com
Content-Length: 139
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: vulnerable-site.com
Foo: x

Cách thức mất đồng bộ xảy ra:

  1. Front-end (CL): Nó đọc 139 byte. Bao gồm tất cả mọi thứ từ số 0 xuống đến Foo: x. Nó chuyển toàn bộ khối này cho backend.
  2. Back-end (TE): Nó tìm kiếm các chunk. Nó thấy số 0 theo sau bởi một dòng trống và giả định rằng yêu cầu đã kết thúc.
  3. Bộ đệm bị nhiễm độc (Poisoned Buffer): Back-end dừng lại ở số 0. Các byte còn lại (phần GET /admin) nằm chờ trong bộ đệm mạng.
  4. Hệ quả: Khi người dùng tiếp theo gửi một yêu cầu, back-end sẽ dán phần GET /admin bị smuggled đó vào phía trước yêu cầu hợp lệ của người dùng. Bạn đã chiếm quyền điều khiển kết nối tiếp theo thành công.

Để tự động tìm kiếm, extension HTTP Request Smuggler trong Burp là không thể thiếu. Nó xử lý các tác vụ tẻ nhạt như tính toán độ lệch byte và thử nghiệm các kỹ thuật xáo trộn (obfuscation) khác nhau.

Phòng thủ thực tế: Thắt chặt bảo mật hệ thống

Việc khắc phục lỗi này không chỉ đơn giản là một bản vá duy nhất. Nó đòi hỏi sự nhất quán trong kiến trúc. Dưới đây là ba chiến lược tôi sử dụng trong môi trường thực tế để thắt chặt bảo mật hệ thống từ gốc.

1. Chuyển sang HTTP/2

Cách khắc phục hiệu quả nhất là chuyển sang HTTP/2 cho toàn bộ chuỗi kết nối. HTTP/2 sử dụng cơ chế binary framing thay vì các header dạng văn bản để xác định ranh giới thông điệp. Điều này loại bỏ hoàn toàn sự mơ hồ giữa CL và TE. Nếu bạn bắt buộc phải sử dụng HTTP/1.1 nội bộ, hãy đảm bảo proxy front-end của bạn thực hiện kiểm tra nghiêm ngặt trước khi hạ cấp (downgrade) yêu cầu.

2. Vô hiệu hóa Chunked Encoding trên Backend

Nếu API của bạn không yêu cầu truyền các tập dữ liệu lớn (streaming), hãy vô hiệu hóa Transfer-Encoding trên các máy chủ nội bộ. Hầu hết các máy chủ web hiện đại có thể được cấu hình để từ chối bất kỳ yêu cầu nào chứa cả hai header. Ví dụ, Nginx thường mặc định từ chối các yêu cầu này trong các phiên bản mới, nhưng bạn nên luôn kiểm tra lại bản build cụ thể của mình.

3. Triển khai Reverse Proxy bảo mật

Sử dụng các phiên bản mới của Envoy hoặc HAProxy. Chúng được thiết kế để tuân thủ nghiêm ngặt các tiêu chuẩn giao thức. Chúng sẽ loại bỏ các yêu cầu sai định dạng hoặc mơ hồ trước khi chúng chạm đến logic ứng dụng của bạn.

# Ví dụ logic thắt chặt bảo mật Nginx
http {
    # Từ chối các header có dấu gạch dưới hoặc ký tự không hợp lệ
    ignore_invalid_headers on;
    
    # Ngăn chặn proxy chuyển tiếp các header mã hóa mơ hồ
    proxy_hide_header Transfer-Encoding;
}

Tổng kết

HTTP Request Smuggling là một mối đe dọa có tác động lớn vì nó biến chính cơ sở hạ tầng của bạn thành công cụ chống lại bạn. Bằng cách hiểu rõ sự không khớp trong cách proxy và backend diễn giải header, bạn có thể lấp đầy các khoảng trống này trước khi kẻ tấn công tìm thấy chúng. Hãy hướng tới sự nhất quán tuyệt đối về giao thức trong toàn bộ hệ thống. Đừng bao giờ mặc định rằng WAF của bạn nhìn thấy cùng một thứ mà máy chủ ứng dụng của bạn thấy.

Share: