SecLab

HTTP request smuggling

CWE-444
01

Là gì

HTTP request smuggling là khi hai máy chủ trên cùng một đường — thường một reverse proxy/CDN ở trước và một backend ở sau — bất đồng về chỗ một request kết thúc. Kẻ tấn công lợi dụng sự bất đồng đó để nhét phần đầu của một request thứ hai vào cuối request thứ nhất, và phần đó được backend xử lý như một request riêng — nhưng gắn vào kết nối của người dùng kế tiếp.

02

Vì sao bạn quan tâm

Mức liên quan: Nên biếtKỳ vọng: L1

Đây là topic mà bản vá gần như không nằm trong code ứng dụng của bạn — nó nằm ở cấu hình giữa proxy và backend, và ở việc hai bên có nói cùng một phiên bản HTTP hay không.

Ba điều làm nó đáng sợ hơn vẻ ngoài:

  • Nó tấn công người dùng KHÁC. Không như phần lớn lỗ hổng chỉ hại chính request của kẻ tấn công, phần request bị smuggle gắn vào kết nối của nạn nhân kế tiếp dùng chung connection — nên kẻ tấn công đánh cắp được request của người khác, hoặc chèn response cho họ.
  • Nó vòng qua mọi kiểm soát ở tầng trước. WAF, xác thực, rate limit ở proxy nhìn thấy request thứ nhất là hợp lệ; phần smuggle không đi qua chúng vì proxy không coi nó là một request.
  • Nó không xuất hiện trong test một-request. Cần đúng hai request và một connection dùng chung, nên nó vô hình với gần như mọi bộ test.

Và tin tốt về mặt phòng chống: nguyên nhân gốc là HTTP/1.1 và cách nó xác định độ dài body (Content-Length vs Transfer-Encoding: chunked). HTTP/2 end-to-end đóng gần như toàn bộ lớp lỗi này, vì nó có một cách duy nhất, tường minh, để xác định độ dài. Nên bản vá mạnh nhất là kiến trúc: HTTP/2 từ client tới backend, không downgrade về HTTP/1.1 ở giữa.

03

Cơ chế hoạt động

Cơ chế là sự bất đồng về cách đọc độ dài body. HTTP/1.1 có hai cách — Content-LengthTransfer-Encoding: chunked — và khi một request có cả hai, chuẩn nói phải ưu tiên chunked, nhưng không phải server nào cũng làm đúng.

Nguồn sơ đồ
sequenceDiagram    autonumber    actor A as Kẻ tấn công    participant P as Proxy (đọc Content-Length)    participant B as Backend (đọc Transfer-Encoding)    A->>P: POST có CẢ Content-Length: 6<br/>VÀ Transfer-Encoding: chunked<br/>body chứa một request lén    Note over P: Proxy theo Content-Length → thấy MỘT request,<br/>chuyển nguyên xi sang backend.    P->>B: chuyển cả cụm byte    Note over B: Backend theo Transfer-Encoding → thấy request<br/>kết thúc SỚM hơn, phần dư là ĐẦU của<br/>một request mới, giữ lại trong buffer.    actor V as Nạn nhân    V->>P: GET / bình thường    P->>B: chuyển request của nạn nhân    Note over B: Phần dư + request nạn nhân GỘP lại →<br/>request của nạn nhân bị đổi, hoặc bị bắt.

Điểm cốt lõi: phần smuggle gắn vào request của nạn nhân kế tiếp trên cùng connection proxy↔backend. Đây là lý do nó tấn công người khác chứ không chỉ chính kẻ tấn công — và là lý do nó không xuất hiện trong test một-request.

Bốn biến thể, đặt tên theo bên nào đọc header nào:

TênProxy đọcBackend đọcGhi chú
CL.TEContent-LengthTransfer-EncodingCổ điển
TE.CLTransfer-EncodingContent-LengthNgược lại
TE.TEcả hai, nhưng khác cách chuẩn hoáMột bên bị lừa bỏ TE bằng header dị dạng
H2.CL / H2.TEHTTP/2 ở trước, HTTP/1.1 ở sauDowngrade tạo lại lỗ ngay cả khi client dùng HTTP/2

Hàng cuối quan trọng: nhiều người nghĩ dùng HTTP/2 ở CDN là đủ, nhưng nếu CDN downgrade về HTTP/1.1 để nói với backend thì toàn bộ lớp lỗi quay lại — và tệ hơn, vì HTTP/2 cho phép những header mà HTTP/1.1 cấm, tạo ra các biến thể mới (request splitting qua header injection).

Mô tả sơ đồ: Sơ đồ tuần tự cho một tấn công CL.TE. Kẻ tấn công gửi một POST có cả Content-Length lẫn Transfer-Encoding chunked, với body chứa một request lén. Proxy đọc theo Content-Length nên thấy chỉ một request và chuyển nguyên cụm byte sang backend. Backend đọc theo Transfer-Encoding nên thấy request kết thúc sớm hơn và giữ phần dư — đầu của một request mới — trong buffer. Khi một nạn nhân gửi một GET bình thường qua cùng proxy, backend gộp phần dư với request của nạn nhân, nên request của nạn nhân bị đổi hoặc bị bắt lại.

04

Ví dụ cụ thể

Một payload CL.TE. Điểm mấu chốt là request có cả hai header xác định độ dài.

HTTP
POST / HTTP/1.1Host: app.exampleContent-Length: 6Transfer-Encoding: chunked 0\r\n\r\nGPOST / HTTP/1.1\r\nFoo: x

Proxy đọc Content-Length: 6 → thân là 0\r\n\r\n (đúng 6 byte tính cả CRLF), chuyển nguyên cụm. Backend đọc Transfer-Encoding: chunked → thấy chunk 0 là kết thúc, nên GPOST / HTTP/1.1...đầu của một request mới giữ lại trong buffer.

HTTP
# Request của nạn nhân tới ngay sau, trên cùng connection proxy↔backend:GET /home HTTP/1.1Host: app.exampleCookie: session=<phiên của NẠN NHÂN>
HTTP
# Backend gộp phần dư với request nạn nhân, nên nó thấy:GPOST /home HTTP/1.1     ← method rác, hoặc tệ hơn: một POST tới /adminFoo: xGET /home HTTP/1.1Host: app.exampleCookie: session=<phiên nạn nhân>
Shell
# Phát hiện bằng độ trễ (không cần nạn nhân thật). Payload CL.TE làm backend# ĐỢI thêm byte không bao giờ tới → response chậm bất thường.time curl -s -o /dev/null https://app.example/ \  -H 'Content-Length: 4' -H 'Transfer-Encoding: chunked' \  --data-binary $'1\r\nA\r\nX'# Nếu request treo ~10s rồi mới trả → dấu hiệu bất đồng CL/TE.
YAMLCấu hình để lộ: HTTP/2 ở client nhưng downgrade về HTTP/1.1 với origin, và không kiểm request mơ hồ.
# nginx trước một backend Kestrel. Trông ổn, và nó để lộ smuggling.nginx_vulnerable: |  server {      listen 443 ssl http2;          # ✓ HTTP/2 với CLIENT      server_name app.example;       location / {          # ❌ proxy_pass mặc định nói HTTP/1.1 với upstream. Nên dù client dùng          #    HTTP/2, có một bước DOWNGRADE về HTTP/1.1 ở đây — và toàn bộ lớp lỗi          #    desync quay lại (biến thể H2.CL/H2.TE ở khối 3).          #          #    "CDN của chúng ta dùng HTTP/2" là câu che giấu đúng dòng này.          proxy_pass http://kestrel_backend;           # ❌ Và không có gì từ chối request mơ hồ. nginx chuyển tiếp request có          #    cả Content-Length lẫn Transfer-Encoding, và Kestrel có thể đọc độ          #    dài body KHÁC cách nginx đọc.      }  }   # ❌ Và WAF chặn /admin Ở ĐÂY — một kiểm soát CHỈ sống ở proxy. Một request /admin  #    được smuggle vào backend không đi qua location này, nên nó vòng qua WAF hoàn toàn.  #    location /admin { deny all; }
05

Chuyện đã xảy ra

Nghiên cứu của James Kettle (PortSwigger, 2019) — "HTTP Desync Attacks". Bài báo làm sống lại lớp lỗ hổng này (được mô tả lần đầu 2005) và cho thấy nó tồn tại ở quy mô lớn trên các CDN và load balancer thật, kèm kỹ thuật phát hiện bằng độ trễ. Đây là nguồn của bảng biến thể ở khối 3, và là lý do topic này được coi trọng trở lại.

"HTTP/2: The Sequel Is Always Worse" (James Kettle, 2021). Cho thấy chuyển sang HTTP/2 ở CDN không đủ nếu CDN downgrade về HTTP/1.1 để nói với backend — và tệ hơn, downgrade tạo ra các biến thể mới vì HTTP/2 cho phép những header mà HTTP/1.1 cấm. Đây là lý do khối 6 nhấn mạnh HTTP/2 phải là end-to-end.

Và một họ báo cáo bug bounty: smuggling để vòng qua kiểm soát của WAF. Mẫu lặp lại: một request /admin bị WAF ở proxy chặn, nhưng cùng request đó được smuggle vào backend thì không đi qua WAF — vì proxy không coi phần smuggle là một request. Điều này minh hoạ luận điểm khối 2: smuggling vòng qua MỌI kiểm soát ở tầng trước.

06

Cách phòng chống

Lớp 1

HTTP/2 end-to-end — bản vá kiến trúc đóng gần như toàn bộ lớp lỗi

bắt buộc

Nguyên nhân gốc là hai cách xác định độ dài body của HTTP/1.1. HTTP/2 chỉ có một cách, tường minh trong khung dữ liệu, nên sự bất đồng CL/TE không tồn tại được.

Điều kiện là end-to-end: client → CDN → proxy → backend đều nói HTTP/2, không có bước nào downgrade về HTTP/1.1. Đây là phần hay bị hiểu sai — nhiều người dừng ở "CDN dùng HTTP/2" và bỏ qua rằng CDN thường nói HTTP/1.1 với origin. Nếu có một bước downgrade thì lớp lỗi quay lại (biến thể H2.CL/H2.TE ở khối 3), và tệ hơn vì HTTP/2 cho phép header mà HTTP/1.1 cấm.

Khi không downgrade được (backend cũ chỉ nói HTTP/1.1), bước tối thiểu là:

  • Bật xác thực chặt HTTP/1.1 ở proxy: từ chối request có CẢ Content-Length lẫn Transfer-Encoding, từ chối Transfer-Encoding dị dạng, từ chối header trùng lặp.
  • Chuẩn hoá request trước khi chuyển tiếp: proxy dựng lại request từ mô hình đã parse thay vì chuyển byte nguyên xi. Đây là điều một reverse proxy hiện đại (nginx, Envoy) làm nếu cấu hình đúng.
YAML · Layer 1HTTP/2 end-to-end nếu backend hỗ trợ; nếu không, từ chối request mơ hồ và cách ly connection.
# ── Đường 1 (ưu tiên) · HTTP/2 END-TO-END ────────────────────────────────────# Nguyên nhân gốc là hai cách xác định độ dài của HTTP/1.1. HTTP/2 có MỘT cách,# tường minh trong khung, nên bất đồng CL/TE không tồn tại được.nginx_http2_e2e: |  server {      listen 443 ssl;      http2 on;                      # HTTP/2 với client      server_name app.example;       location / {          # grpc_pass hoặc proxy với HTTP/2 tới upstream. Điều kiện là KHÔNG có bước          # nào downgrade về HTTP/1.1 — client → nginx → backend đều HTTP/2.          grpc_pass grpc://kestrel_backend;   # Kestrel bật HTTP/2      }  } # ── Đường 2 · buộc phải HTTP/1.1 → loại bỏ khả năng BẤT ĐỒNG ─────────────────nginx_http1_hardened: |  server {      listen 443 ssl;      http2 on;      server_name app.example;       # Từ chối request mơ hồ. Đây là dòng quan trọng nhất khi phải dùng HTTP/1.1:      # một request có cả hai header xác định độ dài là dị thường, và ĐOÁN chỉ an      # toàn khi backend đoán GIỐNG — điều ta không kiểm soát được.      if ($http_transfer_encoding != "") {          # nginx hiện đại tự bỏ Content-Length khi có Transfer-Encoding hợp lệ,          # nhưng ta chặn tường minh mọi Transfer-Encoding dị dạng.          set $te_ok 0;      }       location / {          proxy_pass http://kestrel_backend;          proxy_http_version 1.1;           # Chuẩn hoá: nginx dựng lại request từ mô hình đã parse, không chuyển byte          # nguyên xi. Đây là điều làm proxy và backend "đọc" cùng một request.          proxy_set_header Connection "";           # Cách ly connection là biện pháp CUỐI khi không nâng được HTTP/2: nếu mỗi          # request có connection riêng thì phần smuggle không có request kế tiếp nào          # để gắn vào. Tốn hiệu năng, nên chỉ dùng khi buộc phải.          # proxy_set_header Connection "close";      }  } # ── Kestrel: từ chối request mơ hồ ở CẢ backend ─────────────────────────────# Phòng thủ chiều sâu: kể cả proxy để lọt, backend cũng phải từ chối.kestrel: |  builder.WebHost.ConfigureKestrel(o =>  {      // Bật HTTP/2 để đường 1 khả thi.      o.ConfigureEndpointDefaults(e => e.Protocols = HttpProtocols.Http1AndHttp2);      // Kestrel mặc định đã từ chối request có cả CL lẫn TE (trả 400) từ .NET 5+ —      // nhưng kiểm bằng test ở khối 7 vì đây là bất biến ta KHÔNG được để mất.  });
Lớp 1b

Proxy và backend phải dùng CÙNG một cách xác định độ dài

bắt buộc

Smuggling là một sự bất đồng, nên biện pháp trực tiếp là loại bỏ khả năng bất đồng — kể cả khi buộc phải dùng HTTP/1.1.

  • Từ chối request mơ hồ ở proxy. Một request có cả Content-Length lẫn Transfer-Encoding là dị thường — RFC 9112 nói phải ưu tiên Transfer-Encoding và bỏ Content-Length, nhưng cách an toàn là từ chối 400 thay vì đoán. Cấu hình proxy để làm thế.
  • Dùng cùng một stack ở cả hai đầu nếu được. Bất đồng xảy ra vì proxy và backend parse HTTP bằng code khác nhau. Nếu cả hai là cùng một sản phẩm (hoặc cùng thư viện HTTP) thì chúng chuẩn hoá giống nhau.
  • Tắt tái sử dụng connection giữa proxy và backend (proxy_http_version 1.1 + Connection: close, hoặc dùng connection pool ngắn) là biện pháp cuối: nếu mỗi request có connection riêng thì phần smuggle không có "request kế tiếp" nào để gắn vào. Nó tốn hiệu năng, nên chỉ dùng khi không nâng được lên HTTP/2.

Điểm quan trọng: đây là cấu hình hạ tầng, không phải code ứng dụng. Bản vá sống trong file cấu hình nginx/Envoy/CDN, và nó phải được kiểm bằng test ở tầng đó (khối 7).

Lớp 2

Đừng để một kiểm soát bảo mật CHỈ sống ở tầng proxy

Khối 2 nói smuggling vòng qua mọi kiểm soát ở tầng trước. Nên biện pháp là: đừng đặt kiểm soát quan trọng chỉ ở proxy.

  • Phân quyền phải ở backend, không ở "proxy chặn /admin". Một quy tắc WAF chặn đường dẫn là kiểm soát mà smuggling vòng qua trực tiếp — vì proxy không coi phần smuggle là một request nên không áp quy tắc lên nó. Xem topic access-control: phân quyền thuộc về câu truy vấn, không thuộc về middleware, càng không thuộc về một tầng khác máy.
  • Xác thực phải ở backend. Nếu backend tin "proxy đã xác thực rồi" thì một request smuggle thẳng vào backend không có xác thực nào.

Đây là một hệ quả của nguyên tắc chung: một kiểm soát chỉ đúng khi nó ở đúng tầng mà nó bảo vệ. Smuggling là ví dụ cực đoan vì nó cho phép bỏ qua hẳn một tầng.

Lớp 3

Phát hiện: response ghép sai và độ trễ bất thường

Smuggling để lại hai dấu vết đo được, và cả hai đều bất thường trong lưu lượng bình thường:

  • Response ghép sai request. Một người dùng nhận response của người khác là dấu hiệu rõ nhất, và cũng là báo cáo hỗ trợ khách hàng khó chịu nhất — "tôi thấy đơn hàng của người lạ". Log và alert khi một response có nội dung không khớp phiên của request.
  • Độ trễ bất thường theo cụm. Kỹ thuật phát hiện bằng timing ở khối 4 để lại một chữ ký: request treo ~10s vì backend đợi byte không tới. Một chuỗi request timeout ở tầng proxy trong khi backend khoẻ mạnh là chữ ký của một lần dò desync.
  • Connection header dị thường và method rác (GPOST, POSTGET) trong access log backend. Chúng là mảnh của một request bị ghép, và chúng gần như không xuất hiện tự nhiên.

Đây là lớp 3 vì nó không chặn gì. Nhưng smuggling là lớp lỗi mà nạn nhân không biết mình bị hại (request của họ bị đổi âm thầm), nên phát hiện ở tầng vận hành là cách duy nhất biết nó đang xảy ra.

07

Kiểm chứng đã vá

Topic này có một đặc điểm riêng: phần lớn phép kiểm chạy ở tầng hạ tầng, không ở tầng ứng dụng, và test một-request không bao giờ tìm ra nó.

1. Kiểm proxy TỪ CHỐI request mơ hồ — đây là phép kiểm trực tiếp cho lớp 1b:

Shell
B=https://app.example# Request có CẢ Content-Length lẫn Transfer-Encoding phải bị 400, không được đoán.printf 'POST / HTTP/1.1\r\nHost: app.example\r\nContent-Length: 6\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n' \  | openssl s_client -quiet -connect app.example:443 2>/dev/null | head -1# Mong đợi: HTTP/1.1 400. Nếu là 200 → proxy đang đoán, và nó có thể đoán khác backend.

2. Kiểm HTTP/2 có phải end-to-end — đây là phép kiểm bắt được lỗi mà "CDN dùng HTTP/2" che giấu:

Shell
# Client tới CDN — thường là HTTP/2, dễ kiểm:curl -sI --http2 "$B/" -o /dev/null -w 'client↔cdn: %{http_version}\n'# CDN tới origin — phải kiểm ở CẤU HÌNH CDN, không kiểm từ ngoài được.# Trong nginx/Envoy: grep protocol dùng để nói với upstream.grep -rE 'proxy_http_version|http2.*upstream|http_protocol_options' deploy/ \  | grep -v '1.1' || echo "CẢNH BÁO: upstream có thể đang là HTTP/1.1 (downgrade)"

3. Dùng công cụ chuyên dụng, không tự viết. Smuggling detection cần gửi byte thô với timing chính xác — HTTP Request Smuggler (extension của Burp) và smuggler.py làm việc đó. Chạy chúng trên staging trong pipeline nightly:

Shell
python3 smuggler.py -u https://staging.example.com/ | tee /tmp/smug.txtgrep -qi 'potentially vulnerable\|CL.TE\|TE.CL' /tmp/smug.txt \  && { echo "phát hiện desync"; exit 1; }exit 0

4. Kiểm không có kiểm soát bảo mật CHỈ ở proxy (lớp 2) — smuggling vòng qua tầng proxy, nên một quy tắc WAF chặn /admin phải được backend cũng cưỡng chế:

Shell
# Gọi backend TRỰC TIẾP (bỏ qua proxy) tới một đường mà proxy chặn.# Nó phải bị backend từ chối vì phân quyền, không phải chỉ vì proxy chặn.curl -s -o /dev/null -w '%{http_code}\n' http://backend-internal:5100/admin/users# Mong đợi 401/403 từ chính backend, không phải 200.

5. Alert độ trễ và method rác trong access log (lớp 3). Đây là phép kiểm vận hành, không phải một test — nhưng nó là cách duy nhất biết smuggling đang xảy ra trên production, vì nạn nhân không báo cáo được thứ họ không thấy.

PythonTest smuggling cần HAI request và một connection dùng chung — đây là điểm test một-request bỏ lỡ.
import socketimport sslimport time import pytest HOST = "staging.example.com"  def _raw_request(payload: bytes, read_timeout: float = 12.0) -> tuple[bytes, float]:    """Gửi BYTE THÔ và đo thời gian. Không dùng requests/httpx: chúng chuẩn hoá    header, và chuẩn hoá là chính thứ ta đang cố phá để kiểm."""    ctx = ssl.create_default_context()    with socket.create_connection((HOST, 443), timeout=15) as raw:        with ctx.wrap_socket(raw, server_hostname=HOST) as s:            s.sendall(payload)            s.settimeout(read_timeout)            start = time.monotonic()            data = b""            try:                while chunk := s.recv(4096):                    data += chunk            except (socket.timeout, TimeoutError):                pass            return data, time.monotonic() - start  class TestNoSmuggling:    """Các test này chạy ở tầng HẠ TẦNG, trên byte thô — không ở tầng ứng dụng.    Một test qua requests.post() không bao giờ tìm ra smuggling, vì thư viện đó    không gửi được một request có cả hai header xác định độ dài."""     def test_proxy_rejects_both_length_headers(self):        """Lớp 1b: request có CẢ Content-Length lẫn Transfer-Encoding phải bị 400.         ĐOÁN chỉ an toàn khi backend đoán giống proxy — và ta không kiểm soát được        điều đó, nên câu trả lời đúng là TỪ CHỐI."""        payload = (            b"POST / HTTP/1.1\r\n"            b"Host: " + HOST.encode() + b"\r\n"            b"Content-Length: 6\r\n"            b"Transfer-Encoding: chunked\r\n"            b"\r\n"            b"0\r\n\r\n"        )        response, _ = _raw_request(payload)        status = response.split(b"\r\n", 1)[0]         assert b"400" in status, f"request mơ hồ không bị từ chối: {status!r}"     def test_clte_probe_does_not_hang(self):        """Phát hiện bằng độ trễ (khối 4). Payload CL.TE làm backend ĐỢI byte không        tới → response chậm ~10s. Một response NHANH nghĩa là không có bất đồng."""        payload = (            b"POST / HTTP/1.1\r\n"            b"Host: " + HOST.encode() + b"\r\n"            b"Content-Length: 4\r\n"            b"Transfer-Encoding: chunked\r\n"            b"\r\n"            b"1\r\nA\r\nX"        # chunk 1 byte rồi rác — backend TE sẽ đợi tiếp        )        _, elapsed = _raw_request(payload, read_timeout=12.0)         # Nếu treo gần hết timeout → backend đọc TE trong khi proxy đọc CL: desync.        assert elapsed < 5.0, f"response treo {elapsed:.1f}s — dấu hiệu bất đồng CL/TE"     def test_junk_method_from_desync_is_not_processed(self):        """Nếu một request GPOST (mảnh của request bị ghép) tới được backend và        được XỬ LÝ như một request, đó là desync. Backend phải trả 400 cho method        không hợp lệ, không phải 200."""        payload = (            b"GPOST / HTTP/1.1\r\n"            b"Host: " + HOST.encode() + b"\r\n\r\n"        )        response, _ = _raw_request(payload, read_timeout=5.0)        status = response.split(b"\r\n", 1)[0]         assert b"400" in status or b"501" in status, f"method rác được xử lý: {status!r}"
08

Sai lầm thường gặp

"Bản vá"Vì sao không đúng
Chuyển CDN sang HTTP/2 rồi coi là xongNếu CDN downgrade về HTTP/1.1 để nói với origin thì lớp lỗi quay lại (H2.CL/H2.TE). HTTP/2 phải END-TO-END
Chặn payload smuggling ở WAFWAF thấy request thứ nhất là hợp lệ. Phần smuggle không đi qua WAF vì proxy không coi nó là request
Proxy "ưu tiên Transfer-Encoding theo RFC"Đúng theo chuẩn, nhưng an toàn hơn là TỪ CHỐI request mơ hồ. Đoán đúng chỉ an toàn khi backend đoán GIỐNG
Đặt phân quyền ở quy tắc proxy chặn /adminSmuggling vòng qua nó trực tiếp. Phân quyền thuộc backend — xem topic access-control
Test một requestSmuggling cần đúng hai request và một connection dùng chung. Test một-request luôn xanh
Tự viết script phát hiệnCần timing chính xác và byte thô. Dùng smuggler.py / HTTP Request Smuggler
Tin rằng backend hiện đại miễn nhiễmBất đồng nằm giữa HAI stack, không trong một stack. Backend hoàn hảo + proxy cũ vẫn desync

Sai lầm về vị trí, và nó là sai lầm chính: đi tìm trong code ứng dụng. Smuggling là một lỗi của ranh giới giữa hai máy chủ, nên nó không nằm trong bất kỳ file .cs nào. Bản vá sống trong cấu hình nginx/Envoy/CDN, và nó được kiểm ở tầng đó.

Sai lầm về mức độ: coi nó "khó khai thác nên rủi ro thấp". Nó tấn công NGƯỜI DÙNG KHÁC, vòng qua mọi kiểm soát ở tầng trước, và nạn nhân không biết mình bị hại. Khó dựng không phải là hiếm — các công cụ ở khối 7 làm việc dựng thành tự động.

09

Nguồn tham khảo

Nằm trong lộ trình
Secure Backend DeveloperXem lộ trình

Bình luận

Tham gia thảo luận
Đăng ký để bình luận

Bình luận cần tài khoản đã hoàn thành ít nhất một bài học. Điều kiện đó là thứ giữ cho luồng thảo luận này còn đáng đọc: mỗi ý kiến gắn với một người có thể bị hỏi lại, và reputation tích luỹ theo thời gian.

Đăng kýĐăng nhập

Bạn vẫn đọc được toàn bộ bình luận dưới đây mà không cần tài khoản. Đăng nhập xong bạn sẽ quay lại đúng chỗ này, không phải đầu trang.

Đang tải bình luận…