Trong bức tranh an ninh mạng năm 2026, các cuộc tấn công từ chối dịch vụ phân tán (DDoS — Distributed Denial of Service) đã dịch chuyển mạnh mẽ từ hình thức làm ngập băng thông tầng mạng (Volumetric Layer 3/Layer 4 Flood) sang tấn công cạn kiệt tài nguyên tầng ứng dụng (Layer 7 Application-Layer DDoS). Khác với các đợt tấn công UDP Amplification hay SYN Flood có thể dễ dàng bị phát hiện và lọc bỏ bởi thiết bị scrubbing của nhà mạng nhờ dấu hiệu gói tin dị dạng, một cuộc tấn công HTTP/2 hoặc HTTP/3 Flood ở tầng 7 được thực thi bởi mạng lưới Botnet dân cư (Residential Proxy Botnets) hoàn thành đầy đủ bắt tay TCP 3 bước, đàm phán TLS 1.3 hợp lệ và gửi các truy vấn HTTP trông hoàn toàn giống với hành vi của người dùng thật.
Khi hàng vạn yêu cầu mỗi giây nhắm thẳng vào các điểm cuối không được lưu đệm (Cache-Bypass Search, Login POST, Checkout API), cơ sở dữ liệu và Worker Pool phía sau sẽ gục ngã chỉ trong vài giây dù băng thông đường truyền mới chỉ sử dụng chưa tới 5%. Thiết lập cơ chế phòng chống tấn công DDoS Layer 7 với Nginx Rate Limiting (ngx_http_limit_req_module, ngx_http_limit_conn_module) kết hợp điều tiết hai pha (Two-Stage Rate Limiting) và tự động leo thang chặn IP xuống nhân Linux (Fail2ban + nftables) là tuyến phòng thủ sống còn của mọi kỹ sư SRE và Quản trị hệ thống. Bài viết này phân tích chi tiết mô hình toán học của thuật toán Leaky Bucket trong bộ nhớ dùng chung của Nginx 1.26+/1.27+, kỹ thuật chống giả mạo IP sau CDN, vá lỗ hổng HTTP/2 Rapid Reset (CVE-2023-44487), chống Slowloris và cung cấp trọn bộ cấu hình Production sẵn sàng triển khai.
- 1. Giải phẫu Tấn công DDoS Tầng Ứng dụng (Layer 7) và Tại sao Tường lửa L3/L4 Bất lực?
- 1.1. Sự bất đối xứng chi phí tính toán (Computational Asymmetry): 1 gói tin Client đổi lấy 100ms CPU & Disk I/O ở Backend
- 1.2. Phân loại 4 Kịch bản Tấn công Layer 7 Điển hình: Cache-Bypass Flood, Credential Stuffing, Slowloris và HTTP/2 Rapid Reset (CVE-2023-44487)
- 2. Cơ sở Toán học Thuật toán Leaky Bucket trong ngx_http_limit_req_module và Quản lý Bộ nhớ Shared Zone
- 2.1. Cách Nginx tính toán tốc độ trên từng mili-giây và công thức cấp phát Shared Memory ($binary_remote_addr)
- 2.2. Đặt lên bàn cân 3 Chế độ Thực thi: Mặc định (Queue Delay), burst + nodelay và Two-Stage Rate Limiting (burst=20 delay=10)
- 3. Thiết kế Cấu hình Nginx Chống DDoS Đa Tầng: Phân vùng Endpoint, limit_conn và Bảo vệ khỏi Proxy Spoofing
- 3.1. Chống tự khóa nhầm IP của CDN/Load Balancer bằng ngx_http_realip_module (set_real_ip_from & CF-Connecting-IP)
- 3.2. Thiết lập Whitelist động bằng geo & map và Phân tách 3 Vùng Giới hạn Tốc độ (auth_zone, api_zone, general_zone)
- 4. Chặn Đứng Slowloris, Slow POST và HTTP/2 Rapid Reset bằng Tinh chỉnh Timeout & Stream Limits
- 4.1. Cắt đứt kết nối rỉ rả với client_header_timeout, client_body_timeout, send_timeout và reset_timedout_connection on
- 4.2. Vá triệt để biến thể HTTP/2 Rapid Reset với http2_max_concurrent_streams và keepalive_requests
- 5. Tự động hóa Leo thang Chặn IP xuống Tầng Kernel (nftables) với Fail2ban v1.1+
- 5.1. Tại sao trả về HTTP 429 ở tầng 7 vẫn tốn tài nguyên khi gặp Botnet hung hãn?
- 5.2. Cấu hình Fail2ban jail.local tích hợp nftables-multiport
- 6. Kiểm thử Chịu tải kịch bản DDoS, Giám sát Metrics & Tài liệu Tham khảo Chuẩn Kỹ thuật
- 6.1. Kịch bản Giám sát Thực chiến và Trích xuất Trạng thái Chặn bằng CLI
- 6.2. Kiểm định Định lượng Cấu hình Two-Stage Rate Limiting bằng Công cụ k6
- 6.3. Tài liệu Tham khảo & Nguồn Chuẩn Kỹ thuật (Primary Technical References)
1. Giải phẫu Tấn công DDoS Tầng Ứng dụng (Layer 7) và Tại sao Tường lửa L3/L4 Bất lực?
1.1. Sự bất đối xứng chi phí tính toán (Computational Asymmetry): 1 gói tin Client đổi lấy 100ms CPU & Disk I/O ở Backend
Điểm cốt lõi khiến tấn công DDoS Layer 7 trở nên đặc biệt nguy hiểm nằm ở Sự bất đối xứng chi phí tính toán (Computational Asymmetry). Để tạo và gửi đi một yêu cầu HTTP GET /api/v1/products/search?q=random_uuid_9812 hoặc POST /api/v1/auth/login, kịch bản tấn công chỉ tiêu tốn vài micro-giây CPU và chưa tới 600 bytes băng thông mạng. Ngược lại, khi yêu cầu đó lọt qua Reverse Proxy để đi vào tầng ứng dụng:
- Dịch vụ xác thực phải thực hiện thuật toán băm mật khẩu chống vét cạn (Argon2id hoặc bcrypt) tiêu tốn từ
60msđến150msthời gian CPU chuyên dụng cho mỗi lần gọi. - Hoặc dịch vụ tìm kiếm phải mở kết nối từ Connection Pool, thực thi truy vấn
ILIKEhoặc Full-Text Search quét hàng triệu bản ghi trên đĩa NVMe của PostgreSQL/MySQL, gây tranh chấp khóa bộ đệm (Buffer Pool Contention).
Ngay cả khi máy chủ Linux đã được tối ưu hóa hàng đợi kết nối tầng nhân theo đúng hướng dẫn tuning Linux Kernel sysctl cho máy chủ chịu tải cao, chỉ cần 500 đến 1.000 RPS nhắm vào đúng các endpoint nặng về CPU/Database cũng đủ làm cạn kiệt toàn bộ luồng xử lý của PHP-FPM, Gunicorn hay Go Upstream, đẩy toàn bộ người dùng hợp lệ vào cảnh nhận lỗi 502 Bad Gateway hoặc 504 Gateway Time-out.
1.2. Phân loại 4 Kịch bản Tấn công Layer 7 Điển hình: Cache-Bypass Flood, Credential Stuffing, Slowloris và HTTP/2 Rapid Reset (CVE-2023-44487)
Trước khi thiết kế bộ quy tắc trên Nginx, kỹ sư hệ thống cần nhận diện chính xác 4 phương thức tấn công Layer 7 phổ biến nhất hiện nay (trong khi các thiết lập tối ưu tốc độ truyền tải thông thường được tách biệt sang bài viết cấu hình tối ưu Nginx Reverse Proxy, HTTP/2 và TLS 1.3 hiệu năng cao):
- HTTP GET/POST Cache-Bypass Flood: Botnet liên tục thay đổi tham số chuỗi truy vấn ngẫu nhiên (
?nocache=1730841...) hoặc gửi phương thứcPOSTnhằm vô hiệu hóa lớp bộ nhớ đệm CDN và Nginxproxy_cache, buộc mọi request phải đánh thẳng vào máy chủ gốc (Origin Server). - Brute-Force & Credential Stuffing API: Gửi hàng chục yêu cầu đăng nhập, lấy lại mật khẩu (
OTP SMS/Email) hoặc kiểm tra thẻ tín dụng mỗi giây từ mỗi địa chỉ IP nhằm vừa dò thông tin đăng nhập, vừa gây cạn kiệt tài nguyên xác thực. - Tấn công Rỉ rả Băng thông Thấp (Slowloris & Slow HTTP POST / R-U-Dead-Yet): Thay vì gửi lượng lớn request, kẻ tấn công mở hàng ngàn kết nối TCP hợp lệ rồi nhỏ giọt từng byte HTTP Header (
X-a: b\r\n) hoặc HTTP Body mỗi 10–15 giây, không bao giờ gửi ký tự kết thúc\r\n\r\n. Mục tiêu là chiếm giữ toàn bộ khe kết nối (worker_connections) mà không kích hoạt cảnh báo lưu lượng cao. - HTTP/2 Rapid Reset (
CVE-2023-44487): Lợi dụng tính năng ghép kênh (Multiplexing) của giao thức HTTP/2. Kẻ tấn công mở một kết nối TCP/TLS duy nhất, bắn liên tiếp hàng ngàn khungHEADERSđể khởi tạo luồng xử lý ở Backend rồi ngay lập tức gửi khungRST_STREAMđể hủy luồng. Máy chủ Nginx hủy luồng cũ nhưng cho phép mở ngay luồng mới trên cùng kết nối mà không tính vào giới hạn đồng thời, tạo ra hàng triệu RPS làm sập CPU máy chủ.
Sơ đồ kiến trúc dưới đây mô tả mô hình phòng thủ DDoS Layer 7 đa tầng kết hợp nhân Linux nftables, Nginx 1.27+ và Fail2ban:
flowchart TD
Incoming["Lưu lượng Truy cập Internet / CDN (Người dùng Hợp lệ + Botnet Layer 7)"]
subgraph Layer1["Tầng 1: Linux Kernel Netfilter (nftables)"]
NftSet["Tập hợp Hash O(1) addr-set-nginx-ddos (Chặn tức thì IP Độc hại ở Tầng Mạng)"]
end
subgraph Layer2["Tầng 2: Nginx Real-IP & Phân loại Lưu lượng"]
RealIP["ngx_http_realip_module (Trích xuất IP Thật từ Trusted CDN CIDR)"]
GeoMap["Bảng Băm geo & map (Miễn trừ Whitelist Healthcheck / Partner)"]
end
subgraph Layer3["Tầng 3: Chống Slowloris & HTTP/2 Rapid Reset"]
ConnGuard["limit_conn_zone + client_header_timeout 10s + http2_max_concurrent_streams 128 + keepalive_requests 1000"]
end
subgraph Layer4["Tầng 4: Thuật toán Leaky Bucket Đa Phân Vùng"]
ReqLimit["Two-Stage limit_req_zone (auth_zone: 6r/m, api_zone: 15r/s, general_zone: 50r/s, burst=20 delay=10)"]
end
Upstream["Cụm Máy chủ Ứng dụng Upstream (An toàn, Độ trễ Thấp)"]
Reject429["Từ chối HTTP 429 Too Many Requests — Ghi sự kiện vào /var/log/nginx/ddos_shield_error.log"]
Fail2ban["Fail2ban v1.1+ Daemon (Phát hiện Lặp lại -> Đẩy IP xuống nftables)"]
Incoming --> NftSet
NftSet -->|"IP Sạch"| RealIP
RealIP --> GeoMap
GeoMap --> ConnGuard
ConnGuard -->|"Vượt ngưỡng Kết nối / Timeout"| Reject429
ConnGuard -->|"Hợp lệ"| ReqLimit
ReqLimit -->|"Trong ngưỡng Tốc độ & Burst"| Upstream
ReqLimit -->|"Vượt ngưỡng Bucket"| Reject429
Reject429 --> Fail2ban
Fail2ban -.->|"Cập nhật Ban Set O(1)"| NftSet
2. Cơ sở Toán học Thuật toán Leaky Bucket trong ngx_http_limit_req_module và Quản lý Bộ nhớ Shared Zone
2.1. Cách Nginx tính toán tốc độ trên từng mili-giây và công thức cấp phát Shared Memory ($binary_remote_addr)
Trái tim của hệ thống phòng chống tấn công DDoS Layer 7 với Nginx Rate Limiting là mô-đun ngx_http_limit_req_module, được cài đặt dựa trên thuật toán Chiếc xô rò rỉ (Leaky Bucket) trong khoa học máy tính: hãy hình tượng một chiếc xô có dung tích bằng giá trị burst, nước (các HTTP request) được đổ vào từ miệng xô với tốc độ bất kỳ, nhưng nước chỉ chảy ra khỏi đáy xô để đi vào máy chủ Backend với tốc độ cố định bằng tham số rate. Nếu nước đổ vào quá nhanh làm tràn xô, phần nước tràn ra ngoài sẽ bị từ chối ngay lập tức.
Một hiểu lầm rất phổ biến là khi cấu hình rate=10r/s (10 requests mỗi giây), Nginx sẽ đếm theo từng khung thời gian 1 giây một. Thực tế, Nginx theo dõi khoảng thời gian giữa các request ở độ phân giải mili-giây (millisecond granularity):
$$\Delta t{\text{min}} = \frac{1000\text{ ms}}{\text{rate (r/s)}} \implies \text{Với } \text{rate} = 10\text{r/s}, \quad \Delta t{\text{min}} = 100\text{ ms}$$
Điều này có nghĩa là nếu không cấu hình tham số burst, Nginx cho phép đúng 1 request mỗi 100 mili-giây. Nếu trình duyệt của người dùng hợp lệ tải trang web và gửi đồng thời 2 request cách nhau 15ms, request thứ hai sẽ bị từ chối ngay lập tức dù trong cả giây đó người dùng mới chỉ gửi đúng 2 request!
Về mặt quản lý bộ nhớ trong vùng nhớ dùng chung giữa các tiến trình Worker (shm_zone), chúng ta bắt buộc phải sử dụng biến $binary_remote_addr thay vì $remote_addr:
- Chuỗi văn bản
$remote_addrchiếm từ7đến15 bytescho IPv4 (hoặc tới39 bytescho IPv6). - Biến nhị phân
$binary_remote_addrluôn cố định đúng4 bytescho IPv4 và16 bytescho IPv6. Trên kiến trúc 64-bit (x86_64/ARM64), mỗi bản ghi trạng thái tốc độ của một IPv4 trong cây đỏ-đen (Red-Black Tree) của Nginx chiếm đúng64 bytes(hoặc128 bytesđối với IPv6). - Do đó, 1 Megabyte (
1m) bộ nhớ Shared Zone lưu trữ được chính xác $\frac{1,048,576}{64} \approx 16,384$ địa chỉ IPv4 đang hoạt động. Khi vùng nhớ đầy, Nginx sẽ tự động xóa bản ghi cũ nhất (LRU); nếu vẫn không đủ chỗ, Nginx trả về lỗi cho các IP mới để bảo vệ bộ nhớ máy chủ. Với hệ thống Production chịu tải lớn, bạn nên cấp phát từ10mđến50m(tương đương160.000đến800.000địa chỉ IP đồng thời).
2.2. Đặt lên bàn cân 3 Chế độ Thực thi: Mặc định (Queue Delay), burst + nodelay và Two-Stage Rate Limiting (burst=20 delay=10)
Để vừa chặn đứng Botnet vừa không bao giờ khóa nhầm trình duyệt hiện đại (vốn thường bắn chùm 8–12 request tải dữ liệu JSON song song qua HTTP/2 Multiplexing lúc mới mở trang), Nginx cung cấp 3 chế độ điều tiết:
Chế độ Cấu hình limit_req |
Cơ chế Xử lý Request trong hàng đợi burst |
Ưu điểm & Nhược điểm Thực tế trên Production |
|---|---|---|
1. Chỉ có burst=20 (Không có nodelay) |
Cho phép xếp hàng tối đa 20 request vượt tốc độ, nhưng bắt các request này phải chờ (MARKDOWN_HASHc9fab33e9458412c527c3fe8a13ee37dMARKDOWNHASH) để nhả ra từ từ đúng mỗi $\Delta t{\text{min}}$ (100ms). |
Nhược điểm lớn: Làm tăng độ trễ hiển thị trang web của người dùng thật và giữ kết nối mở lâu trên Nginx Worker. |
2. burst=20 nodelay |
Cho phép cả 20 request trong ngưỡng burst được chuyển tiếp ngay lập tức (độ trễ 0ms) vào Backend; chỉ làm trống dần các ô trong xô theo tốc độ rate. Request thứ 21 bị từ chối ngay. |
Phản hồi cực nhanh cho trình duyệt, nhưng nếu 1.000 IP cùng bắn đồng thời 20 request ở mili-giây đầu tiên, Backend vẫn chịu một cú sốc 20.000 request tức thời. |
3. Two-Stage Rate Limiting (burst=20 delay=10) — Khuyên dùng 2026 |
Pha 1 (Request 1–10): Chuyển tiếp tức thì không độ trễ (nodelay) cho 10 request đầu tiên.Pha 2 (Request 11–20): Làm chậm tự động ( MARKDOWN_HASH1cb60fd54ebe03bbb2d9029f6192641bMARKDOWNHASH) mỗi $\Delta t{\text{min}}$.Pha 3 (Request > 20): Cắt bỏ ngay với mã HTTP 429. |
Tối ưu nhất: Người dùng thật mở trang web (dưới 10 request đồng thời) có trải nghiệm mượt mà tuyệt đối, trong khi các công cụ cào dữ liệu hoặc flood bị hãm phanh rồi khóa hẳn. |
3. Thiết kế Cấu hình Nginx Chống DDoS Đa Tầng: Phân vùng Endpoint, limit_conn và Bảo vệ khỏi Proxy Spoofing
3.1. Chống tự khóa nhầm IP của CDN/Load Balancer bằng ngx_http_realip_module (set_real_ip_from & CF-Connecting-IP)
Sai lầm thảm khốc nhất khi cấu hình phòng chống tấn công DDoS Layer 7 với Nginx Rate Limiting cho các hệ thống đứng sau Cloudflare, AWS CloudFront, Akamai hoặc HAProxy/ALB là áp dụng limit_req_zone $binary_remote_addr mà chưa cấu hình ngx_http_realip_module. Khi đó, biến $binary_remote_addr không phải là IP của kẻ tấn công, mà là địa chỉ IP của nút biên Cloudflare hoặc AWS Load Balancer! Chỉ sau 1 giây bật cấu hình, Nginx sẽ khóa luôn IP của Cloudflare và đánh sập 100% lưu lượng của toàn bộ người dùng trên hệ thống.
Ngược lại, nếu bạn lấy trực tiếp biến $http_x_forwarded_for làm khóa giới hạn tốc độ mà không xác thực IP nguồn, kẻ tấn công chỉ cần gửi kèm header giả mạo X-Forwarded-For: ở mỗi request để vượt qua hoàn toàn bộ lọc Rate Limit.
Giải pháp chuẩn xác duy nhất là kết hợp hai chỉ thị của ngx_http_realip_module:
- Khai báo danh sách các dải CIDR hợp lệ của CDN/Load Balancer trong
set_real_ip_from(chỉ tin tưởng header chuyển tiếp nếu kết nối TCP đến từ đúng dải mạng này). - Sử dụng
real_ip_header CF-Connecting-IP;(hoặcX-Forwarded-Forvớireal_ip_recursive on;) để Nginx ghi đè an toàn IP thật của Client vào biến$binary_remote_addr.
3.2. Thiết lập Whitelist động bằng geo & map và Phân tách 3 Vùng Giới hạn Tốc độ (auth_zone, api_zone, general_zone)
Một hệ thống thương mại điện tử hay SaaS không thể áp dụng cùng một ngưỡng tốc độ cho mọi đường dẫn URI. Hơn nữa, các máy chủ giám sát nội bộ (Prometheus Blackbox Exporter, Kubernetes Liveness Probe) hoặc cổng Webhook đối tác thanh toán cần được miễn trừ khỏi bộ đếm Rate Limit.
Trong Nginx, bạn không bao giờ nên dùng câu lệnh if để bỏ qua limit_req. Thay vào đó, hãy tận dụng đặc tính thiết kế của Nginx: Nếu khóa đầu vào của limit_req_zone nhận giá trị là chuỗi rỗng "", Nginx sẽ tự động bỏ qua hoàn toàn việc kiểm tra giới hạn tốc độ cho request đó! Bằng cách kết hợp mô-đun geo và map, chúng ta tạo ra biến khóa thông minh $limit_req_key:
- Nếu IP nguồn nằm trong danh sách
geo $allowlist_ip(trả về1),mapánh xạ$limit_req_keythành chuỗi rỗng""$\rightarrow$ Không giới hạn tốc độ. - Nếu IP nguồn là khách truy cập thông thường (
0),mapánh xạ$limit_req_keythành$binary_remote_addr$\rightarrow$ Áp dụng đầy đủ Leaky Bucket.
Đồng thời, theo đúng tiêu chuẩn thiết kế RESTful API chuẩn Enterprise và quản lý phiên bản API, chúng ta đổi mã trạng thái mặc định của Nginx từ 503 Service Temporarily Unavailable (dễ làm hệ thống giám sát hiểu nhầm là máy chủ Backend bị sập) sang mã chuẩn IETF 429 Too Many Requests (limit_req_status 429; limit_conn_status 429;).
Dưới đây là tệp cấu hình /etc/nginx/conf.d/ddos-rate-limit-zones.conf hoàn chỉnh:
# File: /etc/nginx/conf.d/ddos-rate-limit-zones.conf
# Cấu hình Khôi phục IP Thật, Whitelist Động và Phân vùng Leaky Bucket trên Nginx 1.26+/1.27+
# 1. KHÔI PHỤC ĐỊA CHỈ IP THẬT TỪ CLOUDFLARE / LOAD BALANCER (Chống Spoofing & Chống tự khóa CDN)
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 10.0.0.0/8; # Dải mạng Load Balancer nội bộ VPC
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# 2. DANH SÁCH MIỄN TRỪ (WHITELIST) CHO HỆ THỐNG MONITORING & WEBHOOK ĐỐI TÁC
geo $allowlist_ip {
default 0;
127.0.0.1/32 1;
10.240.0.0/16 1; # Cụm Prometheus & Internal Healthcheck
203.0.113.50/32 1; # Cổng Payment Gateway Webhook đối tác
}
# Ánh xạ IP Whitelist thành chuỗi rỗng "" để Nginx tự động bỏ qua bộ đếm Rate Limit
map $allowlist_ip $limit_client_key {
0 $binary_remote_addr;
1 "";
}
# 3. KHAI BÁO 3 VÙNG SHARED MEMORY LEAKY BUCKET THEO MỨC ĐỘ NHẠY CẢM CỦA ENDPOINT
# Vùng 1: Bảo vệ Login, Register, OTP, Reset Password (Cực kỳ nghiêm ngặt: 6 requests/phút = 1 request/10s)
limit_req_zone $limit_client_key zone=auth_strict_zone:20m rate=6r/m;
# Vùng 2: Bảo vệ các API tìm kiếm, thanh toán và truy vấn Database động (15 requests/giây)
limit_req_zone $limit_client_key zone=api_dynamic_zone:30m rate=15r/s;
# Vùng 3: Bảo vệ các trang HTML chung và tài nguyên web (50 requests/giây)
limit_req_zone $limit_client_key zone=general_web_zone:30m rate=50r/s;
# 4. GIỚI HẠN SỐ KẾT NỐI ĐỒNG THỜI TRÊN MỖI IP (Chống chiếm giữ Socket & Trình tải đa luồng)
limit_conn_zone $limit_client_key zone=per_ip_conn_zone:20m;
# 5. CHUẨN HÓA MÃ PHẢN HỒI HTTP 429 & MỨC GHI LOG
limit_req_status 429;
limit_conn_status 429;
limit_req_log_level warn;
limit_conn_log_level warn;
4. Chặn Đứng Slowloris, Slow POST và HTTP/2 Rapid Reset bằng Tinh chỉnh Timeout & Stream Limits
4.1. Cắt đứt kết nối rỉ rả với client_header_timeout, client_body_timeout, send_timeout và reset_timedout_connection on
Thuật toán limit_req chỉ kích hoạt sau khi Nginx đã đọc xong toàn bộ phần HTTP Request Header. Kẻ tấn công Slowloris lợi dụng đúng điểm mù này: chúng mở kết nối nhưng không bao giờ gửi xong phần Header. Với giá trị mặc định client_header_timeout 60s và client_body_timeout 60s của Nginx, một mạng Botnet nhỏ chỉ cần mở vài ngàn kết nối là có thể treo cứng máy chủ suốt hàng giờ.
Để vô hiệu hóa hoàn toàn Slowloris và Slow HTTP POST, chúng ta hạ các ngưỡng thời gian chờ giữa hai lần đọc liên tiếp xuống 10 giây, đồng thời bật chỉ thị reset_timedout_connection on;: khi một kết nối quá hạn, thay vì thực hiện quy trình đóng kết nối TCP 4 bước thông thường (FIN $\rightarrow$ ACK khiến socket bị kẹt ở trạng thái FIN_WAIT1/TIME_WAIT trong bộ nhớ Kernel), Nginx gửi ngay một gói tin TCP RST (Reset) để giải phóng tức thì bộ nhớ RAM và File Descriptor về cho hệ điều hành.
4.2. Vá triệt để biến thể HTTP/2 Rapid Reset với http2_max_concurrent_streams và keepalive_requests
Để ngăn chặn các cuộc tấn công lợi dụng giao thức ghép kênh HTTP/2 Rapid Reset (CVE-2023-44487) trên Nginx 1.25.3+ / 1.26 LTS / 1.27+, ngoài việc luôn cập nhật phiên bản Nginx mới nhất (đã tích hợp bộ giới hạn số lượng luồng khởi tạo trên mỗi vòng lặp sự kiện epoll), chúng ta cần khóa chặt:
http2_max_concurrent_streams 128;: Giới hạn số luồng HTTP/2 song song tối đa trên một kết nối TCP ở mức hợp lý cho trình duyệt.keepalive_requests 1000;: Buộc đóng và tái xác thực kết nối sau mỗi 1.000 request nhằm ngăn chặn việc lạm dụng một kết nối TCP duy nhất để bắn hàng triệu khung điều khiển.
Dưới đây là cấu hình Virtual Host /etc/nginx/sites-available/api.infoteck.vn.conf áp dụng đầy đủ Two-Stage Rate Limiting, giới hạn kết nối, phòng chống Slowloris/HTTP2 Rapid Reset và trả về phản hồi JSON chuẩn RFC 9457 kèm header Retry-After:
# File: /etc/nginx/sites-available/api.infoteck.vn.conf
# Cấu hình Virtual Host Thực thi Phòng thủ DDoS Layer 7 Đa tầng trên Nginx 1.27+
server {
listen 443 ssl reuseport;
http2 on;
server_name api.infoteck.vn;
# 1. CHỐNG TẤN CÔNG SLOWLORIS, SLOW POST & GIẢI PHÓNG SOCKET TỨC THÌ BẰNG TCP RST
client_header_timeout 10s;
client_body_timeout 10s;
send_timeout 10s;
keepalive_timeout 30s;
keepalive_requests 1000;
reset_timedout_connection on;
client_max_body_size 2m;
# 2. KHÓA CHẶT KÊNH GHÉP LUỒNG CHỐNG BIẾN THỂ HTTP/2 RAPID RESET (CVE-2023-44487)
http2_max_concurrent_streams 128;
# 3. GIỚI HẠN KẾT NỐI ĐỒNG THỜI TOÀN CỤC CHO MỖI ĐỊA CHỈ IP (Tối đa 30 kết nối/IP)
limit_conn per_ip_conn_zone 30;
# Ghi nhật ký lỗi riêng biệt để Fail2ban quét tốc độ cao
error_log /var/log/nginx/ddos_shield_error.log warn;
# Định nghĩa phản hồi chuẩn JSON RFC 9457 kèm Header Retry-After khi bị chặn 429
error_page 429 = @rate_limit_exceeded;
location @rate_limit_exceeded {
default_type application/problem+json;
add_header Retry-After 30 always;
add_header Cache-Control "no-store" always;
return 429 '{"type":"https://api.infoteck.vn/errors/rate-limit-exceeded","title":"Too Many Requests","status":429,"detail":"Tốc độ truy cập vượt quá giới hạn an toàn. Vui lòng thử lại sau 30 giây."}';
}
# 4. PHÂN VÙNG 1: CÁC ĐIỂM CUỐI XÁC THỰC NHẠY CẢM (Login, OTP, Password Reset)
# Tốc độ gốc: 6 req/phút | Cho phép burst 5 req, trong đó 3 req đầu không trễ (Two-Stage)
location ~ ^/api/v[12]/(auth/login|auth/otp|auth/forgot-password) {
limit_req zone=auth_strict_zone burst=5 delay=3;
limit_conn per_ip_conn_zone 5;
proxy_pass http://backend_auth_cluster;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 5. PHÂN VÙNG 2: CÁC ĐIỂM CUỐI API NGHIỆP VỤ & TÌM KIẾM ĐỘNG
# Tốc độ gốc: 15 req/giây | Two-Stage: 10 req đầu tức thì (0ms), req 11-20 điều tiết mượt, >20 cắt 429
location /api/ {
limit_req zone=api_dynamic_zone burst=20 delay=10;
limit_conn per_ip_conn_zone 15;
proxy_pass http://backend_api_cluster;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 6. PHÂN VÙNG 3: LƯU LƯỢNG TRANG CHUNG & CHẶN TRỰC TIẾP CÁC SCANNER ĐỘC HẠI BẰNG MÃ 444
location / {
limit_req zone=general_web_zone burst=40 delay=25;
proxy_pass http://backend_web_cluster;
}
}
5. Tự động hóa Leo thang Chặn IP xuống Tầng Kernel (nftables) với Fail2ban v1.1+
5.1. Tại sao trả về HTTP 429 ở tầng 7 vẫn tốn tài nguyên khi gặp Botnet hung hãn?
Khi một địa chỉ IP bị limit_req chặn và trả về mã HTTP 429, Nginx đã bảo vệ thành công máy chủ Backend và cơ sở dữ liệu phía sau. Tuy nhiên, nếu một con Bot tấn công ngoan cố tiếp tục bắn 2.000 RPS vào máy chủ, tiến trình Nginx ở không gian người dùng (User Space) vẫn phải đọc gói tin từ card mạng, giải mã khung TLS 1.3, phân tích cú pháp HTTP Header, tra cứu bảng băm Shared Memory và ghi dòng cảnh báo vào đĩa cứng.
Để giải phóng hoàn toàn Nginx khỏi các IP tấn công dai dẳng, chúng ta sử dụng Fail2ban v1.1+ để đọc tệp /var/log/nginx/ddos_shield_error.log: nếu một địa chỉ IP cố tình vi phạm ngưỡng limiting requests, excess: quá 15 lần trong vòng 60 giây, Fail2ban sẽ tự động đẩy địa chỉ IP đó xuống tập hợp băm (Hash Set O(1)) của tường lửa nhân Linux nftables. Từ giây tiếp theo, mọi gói tin từ IP đó sẽ bị nhân hệ điều hành hủy bỏ ngay tại trình điều khiển mạng với chi phí CPU gần như bằng 0 trước cả khi chạm tới socket của Nginx!
Sơ đồ tuần tự dưới đây minh họa cơ chế hoạt động của Two-Stage Rate Limiting và luồng tự động leo thang chặn IP xuống nftables:
sequenceDiagram
autonumber
participant AttackerBot as Client / Botnet IP
participant NetfilterNft as Linux Kernel nftables (Tầng 3/4)
participant NginxEdge as Nginx 1.27+ Leaky Bucket (Tầng 7)
participant UpstreamApp as Backend API Server
participant Fail2banDaemon as Fail2ban v1.1+ Daemon
Note over AttackerBot,UpstreamApp: Giai đoạn 1: Cụm Burst Hợp lệ (Request 1 -> 10)
AttackerBot->>NetfilterNft: 1. Gửi chùm 10 HTTP/2 Requests đồng thời
NetfilterNft->>NginxEdge: 2. Cho qua (IP chưa nằm trong nftables Ban Set)
NginxEdge->>UpstreamApp: 3. Chuyển tiếp tức thì (0ms Delay - Pha 1 Two-Stage)
UpstreamApp-->>AttackerBot: 4. HTTP 200 OK
Note over AttackerBot,UpstreamApp: Giai đoạn 2: Điều tiết Mượt (Request 11 -> 20)
AttackerBot->>NginxEdge: 5. Gửi tiếp Request 11 -> 20 vượt tốc độ 15r/s
Note over NginxEdge: Áp dụng Pha 2 (delay=10) — Làm chậm từng Request mỗi 66.6ms (1000ms/15)
NginxEdge->>UpstreamApp: 6. Chuyển tiếp có kiểm soát tốc độ
Note over AttackerBot,Fail2banDaemon: Giai đoạn 3: Tấn công Flood (> 20 Requests) & Leo thang Kernel Ban
AttackerBot->>NginxEdge: 7. Bắn dồn dập Request 21 -> 50 (HTTP Flood)
NginxEdge-->>AttackerBot: 8. Cắt kết nối ngay: HTTP 429 Too Many Requests
NginxEdge->>Fail2banDaemon: 9. Ghi log "limiting requests, excess: 20.450 by zone..."
Note over Fail2banDaemon: Đếm đủ maxretry = 15 lần vi phạm trong 60s
Fail2banDaemon->>NetfilterNft: 10. Thực thi: nft add element inet f2b-table addr-set-nginx-req-limit { IP }
AttackerBot->>NetfilterNft: 11. Gửi các gói tin tấn công tiếp theo
Note over NetfilterNft: DROP tức thì ở Kernel (O(1) Hash Lookup) — Nginx tốn 0% CPU!
5.2. Cấu hình Fail2ban jail.local tích hợp nftables-multiport
Dưới đây là cấu hình hoàn chỉnh cho Fail2ban v1.1+ sử dụng hậu tố hành động nftables hiện đại (thay thế iptables tuyến tính cũ kỹ) kèm cơ chế tăng dần thời gian cấm (bantime.increment = true) đối với các IP tái phạm nhiều lần:
# File: /etc/fail2ban/jail.d/nginx-layer7-ddos.local
# Cấu hình Fail2ban v1.1+ tự động leo thang chặn IP vi phạm Nginx Rate Limit xuống Kernel nftables
[DEFAULT]
# Sử dụng bộ lọc tập hợp băm O(1) của Linux Kernel nftables thay vì chuỗi iptables cũ
banaction = nftables[type=multiport]
banaction_allports = nftables[type=allports]
# Không bao giờ khóa nhầm dải mạng nội bộ và Monitoring
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 172.16.0.0/12
# Tự động nhân đôi thời gian khóa nếu IP tái phạm sau khi hết hạn
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 7d
[nginx-req-limit]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/ddos_shield_error.log
findtime = 60s
# Cho phép tối đa 15 lần tràn xô Leaky Bucket trong 60 giây trước khi khóa ở tầng Kernel
maxretry = 15
bantime = 30m
[nginx-conn-limit]
enabled = true
port = http,https
filter = nginx-conn-limit-custom
logpath = /var/log/nginx/ddos_shield_error.log
findtime = 60s
maxretry = 10
bantime = 1h
6. Kiểm thử Chịu tải kịch bản DDoS, Giám sát Metrics & Tài liệu Tham khảo Chuẩn Kỹ thuật
6.1. Kịch bản Giám sát Thực chiến và Trích xuất Trạng thái Chặn bằng CLI
Trong lúc hệ thống đang chịu đợt tấn công thực tế, bên cạnh việc thu thập biểu đồ tự động theo mô hình thiết lập hệ thống Monitoring toàn diện với Prometheus và Grafana, kỹ sư trực chiến (On-Call SRE) có thể chạy ngay kịch bản chẩn đoán dưới đây để thống kê chính xác các IP đang bị Nginx hãm phanh và kiểm tra danh sách IP đã bị khóa ở tầng nhân nftables:
#!/usr/bin/env bash
# File: ddos-live-forensics.sh
# Kịch bản chẩn đoán trực tiếp trạng thái Nginx Rate Limit và tập hợp chặn Kernel nftables
set -Eeuo pipefail
echo "=== [1/4] Kiểm tra cú pháp cấu hình Nginx trước khi nạp nóng (Zero-Downtime Reload) ==="
nginx -t && systemctl reload nginx
echo "=== [2/4] Top 10 Địa chỉ IP đang bị Nginx Leaky Bucket chặn nhiều nhất trong Error Log ==="
awk '/limiting requests, excess:/ {print $12}' /var/log/nginx/ddos_shield_error.log \
| tr -d ',"' \
| sort \
| uniq -c \
| sort -nr \
| head -n 10
echo "=== [3/4] Kiểm tra trạng thái hàng đợi Socket TCP tầng nhân (Phát hiện SYN/Slowloris) ==="
ss -s
ss -tan state syn-recv | wc -l
echo "=== [4/4] Liệt kê danh sách IP đã bị Fail2ban leo thang khóa cứng trong Kernel nftables ==="
fail2ban-client status nginx-req-limit
nft list set inet f2b-table addr-set-nginx-req-limit 2>/dev/null || true
6.2. Kiểm định Định lượng Cấu hình Two-Stage Rate Limiting bằng Công cụ k6
Không bao giờ đợi đến khi bị tấn công thật mới kiểm tra xem cấu hình limit_req có hoạt động đúng như thiết kế hay không. Bạn có thể sử dụng kịch bản kiểm thử tải k6 dưới đây trên môi trường Staging để xác nhận thực nghiệm rằng 10 request đầu tiên trả về HTTP 200, các request từ 11–20 được điều tiết mượt mà và mọi request vượt ngưỡng đều nhận chính xác mã HTTP 429 kèm header Retry-After:
// File: test-nginx-two-stage-ratelimit.js
// Chạy lệnh: k6 run test-nginx-two-stage-ratelimit.js
import http from 'k6/http';
import { check } from 'k6';
export const options = {
scenarios: {
burst_flood_simulation: {
executor: 'per-vu-iterations',
vus: 1,
iterations: 30, // Bắn dồn dập 30 requests liên tiếp từ 1 IP
maxDuration: '5s',
},
},
};
export default function () {
const res = http.get('https://api.infoteck.vn/api/v1/catalog/items');
if (__ITER < 20) {
// 20 request đầu tiên (gồm 10 nodelay + 10 delayed trong burst=20) phải thành công (HTTP 200)
check(res, {
'Request trong nguong Burst thanh cong (HTTP 200)': (r) => r.status === 200,
});
} else {
// Từ request thứ 21 trở đi khi bắn dồn dập phải bị chặn đứng với HTTP 429 và có Retry-After
check(res, {
'Request vuot nguong bi chan dung (HTTP 429)': (r) => r.status === 429,
'Co tra ve Header Retry-After chuan RFC': (r) => r.headers['Retry-After'] !== undefined,
});
}
}
6.3. Tài liệu Tham khảo & Nguồn Chuẩn Kỹ thuật (Primary Technical References)
Toàn bộ công thức tính toán bộ nhớ Shared Zone, thuật toán Leaky Bucket và cấu hình bảo mật tầng 7 trong bài viết này được tham chiếu trực tiếp từ tài liệu kỹ thuật chính thức của NGINX, IETF, OWASP và CISA:
- NGINX Official Documentation — Module
ngx_http_limit_req_module(Leaky Bucket Rate Limiting & Two-Stage Delay Specification) - NGINX Official Documentation — Module
ngx_http_limit_conn_module(Concurrent Connection Limiting Specification) - NGINX Official Documentation — Module
ngx_http_realip_module(Trusted Proxy Client IP Extraction) - CISA & NIST National Vulnerability Database — CVE-2023-44487 (HTTP/2 Rapid Reset DDoS Vulnerability Technical Advisory)
- OWASP Denial of Service (DoS) Cheat Sheet — Application-Layer Defense & Rate Limiting Architecture
- Netfilter
nftablesOfficial Wiki — High-Performance O(1) Sets and Packet Filtering Architecture