Khi tường lửa tê liệt trước các đợt bão lưu lượng lớn
Quý trước, cụm API chính của chúng tôi hứng chịu một đợt tấn công bão phản xạ UDP dữ dội lợi dụng các resolver DNS (cổng 53) và CLDAP (cổng 389) bị lộ. Trong vòng chưa đầy 15 giây, lưu lượng chiều đến tăng vọt từ mức bình thường 2.4 Gbps lên 48 Gbps, đạt đỉnh khoảng 36 triệu gói tin mỗi giây (Mpps). Các cổng 100 GbE trên đường truyền transit upstream của chúng tôi vẫn còn dư thừa dung lượng. Tuy nhiên, các máy chủ edge Linux lại sụp đổ gần như ngay lập tức.
Băng thông chưa từng là điểm nghẽn. Kẻ hủy diệt thực sự chính là số lượng gói tin mỗi giây (PPS). Từng gói tin tràn vào buộc framework netfilter của Linux phải duyệt qua các bảng theo dõi kết nối có trạng thái (stateful connection tracking). Chỉ trong vài giây, ksoftirqd đã chiếm dụng 100% tài nguyên của mọi nhân CPU, dẫn đến tình trạng rớt gói tin hàng loạt trên ring buffer. Các tiến trình bắt tay TLS hợp lệ bị đình trệ, health check thất bại trên toàn hệ thống và trang báo trạng thái dịch vụ chuyển sang màu đỏ.
Những giải pháp xử lý thông thường chỉ khiến tình hình tồi tệ hơn:
- Remotely Triggered Black Hole (RTBH): Việc quảng bá một route /32 gắn tag
no-exporthoặc blackhole community của nhà cung cấp transit (chẳng hạn65535:666) sẽ loại bỏ được đợt tấn công. Trớ trêu thay, nó cũng đồng thời hủy toàn bộ lưu lượng truy cập hợp lệ của khách hàng tới IP đó. Kẻ tấn công đạt được mục đích mà chẳng tốn nhiều công sức. - Nâng cấp phần cứng tường lửa: Đầu tư thiết bị tường lửa lớn hơn hay bổ sung các node cụm máy chủ mạnh hơn sẽ tiêu tốn đáng kể ngân sách vận hành. Tệ hơn nữa, các thiết bị stateful vẫn sẽ gục ngã khi các đợt flood SYN hoặc UDP làm cạn kiệt bảng trạng thái kết nối.
Nguyên nhân gốc rễ: Chi phí xử lý stateful trên máy chủ vs. Chip xử lý chuyên dụng trên router
Tường lửa phần mềm trên Linux kiểm tra các gói tin sâu bên trong network stack của máy chủ. Ngay cả các kỹ thuật bypass tối ưu như XDP (eBPF) cũng phải chật vật khi các line card và cổng uplink của switch top-of-rack ngập trong các đợt bão lưu lượng ở tốc độ đường truyền (wire-speed).
Các router biên (edge) và router lõi (core) xử lý vấn đề này theo cách hoàn toàn khác. Những nền tảng như Juniper MX series, Cisco ASR 9000 và Arista 7280R phụ thuộc vào bộ nhớ TCAM (Ternary Content-Addressable Memory) chuyên dụng và các ASIC tùy biến. Các ASIC này kiểm tra header của gói tin đồng thời ở tốc độ đường truyền (line rate). Việc lọc 50 triệu gói tin mỗi giây gần như không tiêu tốn thêm bất kỳ chu kỳ CPU nào của chúng.
Trở ngại trong vận hành từ trước đến nay luôn là khâu quản lý. Bạn không thể yêu cầu kỹ sư cấu hình thủ công từng access list trên router lõi vào lúc 3 giờ sáng khi sự cố đang diễn ra. BGP tiêu chuẩn cũng không hỗ trợ việc này, vì các thông điệp thông báo truyền thống chỉ trao đổi các tiền tố định tuyến mạng (prefix reachability). Chúng không thể chỉ định cụ thể các cổng tầng layer 4, giao thức hay kích thước gói tin. Hệ thống đo kiểm telemetry và phát hiện bất thường chạy trên máy chủ Linux, nhưng phần cứng có khả năng triệt tiêu đợt tấn công lại nằm ở phía upstream.
Đánh giá các giải pháp
Để kết nối khả năng phát hiện ở cấp máy chủ với phần cứng định tuyến upstream, thông thường ta có ba kỹ thuật:
1. Unicast BGP RTBH (RFC 3882)
RTBH điều hướng toàn bộ lưu lượng hướng tới IP mục tiêu vào một null interface. Việc thiết lập chỉ cần một vài BGP community tag. Nhược điểm của giải pháp này là độ chi tiết thô ở mức địa chỉ đích /32. Một đợt khuếch đại DNS đơn giản cũng có thể đánh sập toàn bộ endpoint HTTPS dùng chung của nhiều khách hàng (multi-tenant), gây thiệt hại ngoài ý muốn 100%.
2. Tự động hóa Out-of-Band (NETCONF / RESTCONF / SSH)
Các tập lệnh tự động có thể mở phiên SSH hoặc gửi payload NETCONF để tạo ACL trên router theo nhu cầu. Dù hoạt động được, nhưng trong môi trường đa hãng sản xuất (multi-vendor), phương pháp này rất dễ đổ vỡ. Cú pháp giữa các hãng có sự khác biệt, các khóa commit có thể chặn cập nhật khẩn cấp, và một lỗi API không được xử lý trong đợt tấn công sẽ khiến việc lọc gói tin bị dở dang.
3. BGP Flowspec (RFC 8955 / RFC 5575)
BGP Flowspec (AFI 1, SAFI 133) giải quyết triệt để vấn đề độ chi tiết bằng cách xử lý các quy tắc tường lửa như những bản cập nhật định tuyến BGP thông thường. Bạn có thể phân phối các tham số khớp phức tạp—subnet nguồn/đích, giao thức layer 4, dải cổng, mã ICMP và độ dài gói tin—kèm theo các hành động trực tiếp như hủy gói (discard), giới hạn tốc độ (rate-limit) hoặc chuyển hướng VRF. Các quy tắc được đẩy xuyên suốt cấu trúc mạng chỉ trong vài mili-giây qua các phiên peering BGP sẵn có.
Xây dựng bộ điều khiển Flowspec tự động với ExaBGP
ExaBGP đóng vai trò như một engine phần mềm trung gian giữa các ứng dụng Linux và phần cứng mạng hỗ trợ BGP. Nó không can thiệp vào bảng định tuyến của nhân Linux. Thay vào đó, nó biên dịch các lệnh dạng văn bản thuần túy từ standard input hoặc FIFO thành các bản cập nhật BGP gửi trực tiếp đến các router biên của bạn.
Bước 1: Cài đặt ExaBGP
Triển khai ExaBGP trên máy chủ giám sát hoặc phân tích lưu lượng. Ubuntu 22.04 LTS và Debian 12 đều có sẵn các bản cài đặt ổn định, hoặc bạn có thể cài phiên bản mới nhất qua pip:
sudo apt-get update
sudo apt-get install -y python3-pip exabgp
# Hoặc cài đặt trực tiếp qua pip
pip3 install exabgp
Bước 2: Cấu hình Named Pipe để đẩy quy tắc động
Named pipe (FIFO) cho phép các script phát hiện chạy ngầm truyền quy tắc trực tiếp vào tiến trình ExaBGP đang chạy mà không làm gián đoạn phiên kết nối:
sudo mkdir -p /etc/exabgp/run
sudo mkfifo /etc/exabgp/run/exabgp.in
sudo mkfifo /etc/exabgp/run/exabgp.out
sudo chmod 600 /etc/exabgp/run/exabgp.*
Bước 3: Thiết lập cấu hình Peering
Lưu cấu hình sau vào tệp /etc/exabgp/exabgp.conf. Trong mô hình này, controller Linux của chúng ta (192.0.2.10, AS 65001) thiết lập phiên BGP nội bộ với một router upstream (192.0.2.1, AS 65001):
process inject-flowspec {
run /usr/bin/cat /etc/exabgp/run/exabgp.in;
encoder text;
}
neighbor 192.0.2.1 {
router-id 192.0.2.10;
local-address 192.0.2.10;
local-as 65001;
peer-as 65001;
family {
ipv4 flow;
}
api {
processes [ inject-flowspec ];
}
}
Bước 4: Thiết lập phiên BGP
Đảm bảo router upstream của bạn cho phép address family Flowspec (chẳng hạn address-family ipv4 flow-spec trên Cisco IOS-XR hoặc family inet flow trên Juniper Junos). Khởi chạy ExaBGP ở chế độ foreground để xác nhận phiên kết nối khởi tạo thành công:
exabgp /etc/exabgp/exabgp.conf
Quan sát quá trình đàm phán BGP OPEN và trạng thái chuyển sang ESTABLISHED.
Bước 5: Đẩy các quy tắc giảm thiểu có chọn lọc
Giả sử một hệ thống giám sát tự động phát hiện cuộc tấn công khuếch đại DNS 25 Mpps nhắm vào IP cụm web 198.51.100.50. Bạn có thể chặn riêng vector tấn công đó bằng cách đẩy quy tắc discard chọn lọc vào FIFO:
echo "announce flow route destination 198.51.100.50/32 source-port [ =53 ] protocol udp discard" > /etc/exabgp/run/exabgp.in
Router nhận được cập nhật trong chưa đầy một giây. Các ASIC của nó lập tức so khớp các gói tin UDP đi vào có cổng nguồn 53 hướng đến máy chủ đó và loại bỏ chúng ngay ở tầng phần cứng. Trong khi đó, lưu lượng HTTPS hợp lệ trên cổng 443 vẫn lưu thông bình thường.
Bước 6: Tự động hóa việc giới hạn tốc độ chuẩn xác
Hủy gói tin hoàn toàn không phải lúc nào cũng là giải pháp an toàn nhất ban đầu, đặc biệt là khi cần phân biệt giữa lượng truy cập đột biến hợp lệ (flash crowd) với các đợt flood phân tán. Thay vào đó, bạn có thể điều tiết lưu lượng đáng ngờ. RFC 8955 định nghĩa việc giới hạn tốc độ theo byte trên giây. Ví dụ: 125,000 bytes/giây tương đương với việc áp mức trần băng thông 1 Mbps.
Dưới đây là đoạn code mẫu daemon Python tích hợp cảnh báo từ các công cụ như FastNetMon, Prometheus Alertmanager hoặc các bộ thu thập sFlow tự viết:
#!/usr/bin/env python3
import sys
def inject_flowspec_ratelimit(victim_ip: str, port: int, rate_bps: int):
pipe_path = "/etc/exabgp/run/exabgp.in"
# rate_bps được truyền vào theo đơn vị byte/giây: 125,000 bytes/s ~= 1 Mbps
rule = (
f"announce flow route destination {victim_ip}/32 "
f"port [ ={port} ] protocol tcp "
f"rate-limit {rate_bps}\n"
)
try:
with open(pipe_path, "w") as fifo:
fifo.write(rule)
fifo.flush()
print(f"[+] Đã áp dụng giới hạn tốc độ {rate_bps} B/s lên {victim_ip}:{port}")
except BrokenPipeError:
print("[-] Lỗi: Tiến trình lắng nghe ExaBGP FIFO chưa hoạt động", file=sys.stderr)
if __name__ == "__main__":
# Điều tiết lưu lượng bất thường nhắm vào cổng 80 xuống 1 Mbps
inject_flowspec_ratelimit("198.51.100.50", 80, 125000)
Khi dữ liệu đo kiểm cho thấy mức lưu lượng đã ổn định trở lại, hãy thu hồi (withdraw) route để giải phóng tài nguyên bảng TCAM:
echo "withdraw flow route destination 198.51.100.50/32 port [ =80 ] protocol tcp" > /etc/exabgp/run/exabgp.in
Phần cứng định tuyến được thiết kế chuyên biệt để triệt tiêu hàng gigabit dữ liệu rác ở tốc độ đường truyền. Việc đẩy các bộ lọc Flowspec qua ExaBGP giúp giải phóng máy chủ khỏi gánh nặng lọc gói tin lưu lượng lớn, chặn đứng lưu lượng tấn công ngay tại vùng biên trước khi chạm vào hạ tầng của bạn.
