Tấn công SYN Flood là một hình thức tấn công từ chối dịch vụ (DoS) phổ biến, nhắm vào các máy chủ Linux để làm gián đoạn hoạt động của hệ thống, gây nghẽn kết nối và thậm chí khiến máy chủ bị sập hoàn toàn. Trong thời đại số hóa hiện nay, việc bảo vệ máy chủ khỏi các cuộc tấn công mạng ngày càng trở nên quan trọng, đặc biệt là với các doanh nghiệp sở hữu dữ liệu quan trọng hoặc cung cấp dịch vụ trực tuyến.
Nếu không có biện pháp phòng ngừa kịp thời, hậu quả của tấn công SYN Flood có thể rất nghiêm trọng, ảnh hưởng lớn đến uy tín và doanh thu của doanh nghiệp.
Chính vì vậy, việc tìm hiểu cách ngăn chặn tấn công SYN Flood trên máy chủ Linux là điều cần thiết cho các quản trị viên hệ thống. Bài viết dưới đây sẽ hướng dẫn bạn những phương pháp hiệu quả nhất để phòng chống SYN Flood, giúp đảm bảo an ninh cho hệ thống và duy trì hoạt động ổn định cho máy chủ Linux của bạn.

Tấn công SYN Flood là gì?
Một kết nối TCP bình thường bắt đầu với ba bước gọi là Three-Way Handshake: máy khách (client) gửi gói SYN, máy chủ (server) trả lời bằng gói SYN-ACK, rồi máy khách hoàn tất bằng gói ACK.
Sau khi handshake hoàn thành, kết nối được thiết lập và có thể bắt đầu trao đổi dữ liệu.
Trong tấn công SYN flood, kẻ tấn công lợi dụng quá trình handshake này bằng cách gửi nhiều gói SYN hơn khả năng xử lý của server.
Server sẽ gửi trả SYN-ACK nhưng không nhận được gói ACK cuối cùng, khiến các kết nối bị “bán mở” (half-open).
Mỗi kết nối bán mở chiếm tài nguyên của server, và khi có quá nhiều kết nối bán mở, server nhanh chóng hết khả năng xử lý các kết nối hợp lệ mới. Trong trường hợp nghiêm trọng, server có thể bị treo và không phản hồi được.
Tấn công SYN flood có thể là tấn công DoS từ một thiết bị hoặc DDoS từ nhiều thiết bị (thường là botnet).
Loại tấn công này còn được gọi là “tấn công bán mở”.
Cách tôi thử nghiệm
Tôi tạo hai máy ảo trên MacBook, đều chạy Ubuntu 24.04 server. Một máy làm nạn nhân (victim), một máy làm kẻ tấn công (attacker).
Tôi dùng hping3 và ApacheBench để mô phỏng tấn công SYN flood và lượng truy cập lớn.
ApacheBench là công cụ đo hiệu năng web server nhưng cũng có thể dùng để tạo lượng truy cập lớn, thử khả năng chịu tải của server.
Tôi cài NGINX trên máy nạn nhân để mở cổng 80, rồi dùng lệnh:
hping3 -S -p 80 --flood <địa_chỉ_IP>
và theo dõi với:
tcpdump -nn port 80
Tùy chọn --flood gửi liên tục gói SYN mà không hoàn thành handshake, làm server nạn nhân nhanh chóng không phản hồi.
Sau một thời gian, tôi nhận lỗi máy chủ không hoạt động và mất kết nối SSH.
Ngoài ra, tôi chạy ApacheBench với lượng request lớn, làm tài nguyên server tăng cao. Thông thường người dùng không gửi quá nhiều kết nối trong thời gian ngắn như vậy nên đây là dấu hiệu tấn công rõ ràng.
Lúc này tôi chưa cấu hình firewall.
Kích hoạt UFW (Uncomplicated Firewall) trên máy nạn nhân không giúp nhiều vì UFW không có cơ chế chống SYN flood tích hợp.
UFW có quy tắc limit cho SSH nhưng không phù hợp với web server sản xuất vì giới hạn 6 kết nối trong 30 giây có thể chặn nhầm lưu lượng hợp lệ. Với môi trường của tôi, quy tắc này không đủ.
Tôi cần giải pháp tinh chỉnh hơn để ngăn chặn tấn công mà không ảnh hưởng đến khách thật.
Sau nghiên cứu, tôi tạo giải pháp giới hạn số lượng gói SYN mỗi IP trong khoảng thời gian nhất định và ghi lại các lần vượt quá giới hạn. Cách này giúp lọc lưu lượng nguy hiểm mà không gây gián đoạn người dùng thật.
Tôi không sao chép y nguyên các quy tắc từ mạng mà lấy làm cơ sở rồi điều chỉnh, thử nghiệm để tìm ra giải pháp hiệu quả thực sự.
Tôi cũng dùng Fail2ban để quản lý danh sách đen IP thay vì tự duy trì thủ công. Fail2ban hoạt động tốt với UFW nhưng cần cấu hình riêng.
Sau khi xây dựng giải pháp, tôi thử nghiệm trên hai VPS thật của GreenCloud và SpeedyPage thì kết quả rất khả quan.
Lưu ý: Các công cụ như hping3 và ApacheBench chỉ nên dùng để thử nghiệm và phát triển giải pháp bảo mật, không dùng để tấn công người khác.
Cấu hình Kernel
Trước khi thử firewall, tôi điều chỉnh một số tham số kernel để giảm thiểu tấn công SYN flood. Nó có tác dụng nhưng không lớn.
Tôi đã viết hướng dẫn về kernel hardening, trong đó có các thiết lập hỗ trợ chống tấn công SYN flood. Nên bật những thiết lập này dù không hoàn toàn ngăn chặn được tấn công.
Mở file /etc/sysctl.conf, bạn sẽ thấy các tham số sau đang bị comment:
#net.ipv4.conf.default.rp_filter=1
#net.ipv4.conf.all.rp_filter=1
#net.ipv4.tcp_syncookies=1
Tham số net.ipv4.tcp_syncookies đã được bật (1) giúp giảm thiểu tấn công bằng cách quản lý kết nối bán mở mà không chiếm nhiều tài nguyên.
Bạn kiểm tra bằng lệnh:
sudo sysctl net.ipv4.tcp_syncookies
Nếu chưa bật thì bỏ comment dòng trong file /etc/sysctl.conf.
Hai tham số net.ipv4.conf.default.rp_filter và net.ipv4.conf.all.rp_filter hiện đang ở chế độ 2 (loose mode), dùng để lọc địa chỉ IP giả mạo.
Bạn có thể bật ở chế độ nghiêm ngặt hơn (1) bằng cách bỏ comment và chỉnh lại giá trị.
Thêm hai tham số sau để tối ưu:
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_synack_retries = 3
tcp_max_syn_backlogtăng kích thước hàng đợi các yêu cầu SYN mới từ mặc định 256 lên 4096 giúp server chịu tải nhiều kết nối bán mở hơn.tcp_synack_retriesgiảm số lần gửi lại SYN-ACK khi chưa nhận ACK từ client (mặc định là 5), giảm xuống 3 giúp giải phóng tài nguyên nhanh hơn khi client không phản hồi (giúp chống SYN flood).
Lưu file rồi khởi động lại server để áp dụng thay đổi.
Hiểu về các file quy tắc UFW
Trong thư mục /etc/ufw/ có ba file quan trọng: before.rules, before6.rules và user.rules.
before.rulesxử lý quy tắc cho IPv4.before6.rulesxử lý cho IPv6.user.ruleschứa các quy tắc bạn thêm qua lệnh UFW (ví dụ:sudo ufw allow 80/tcp).
Các quy tắc trong file before.rules và before6.rules được áp dụng trước các quy tắc trong user.rules.
Điều này có nghĩa nếu bạn đặt quy tắc chặn HTTP trong before.rules, nó sẽ ưu tiên hơn quy tắc cho phép HTTP trong user.rules.
Bạn nên chỉnh sửa các quy tắc tùy chỉnh trong before.rules hoặc before6.rules, không chỉnh trực tiếp vào user.rules vì file này có thể bị ghi đè khi thay đổi qua lệnh UFW.
Hiểu thứ tự xử lý các file này giúp quản lý firewall chính xác hơn.
Chặn các gói tin không hợp lệ
Kích hoạt firewall và chuẩn bị các quy tắc chống SYN flood bằng cách chặn các gói tin không hợp lệ, chỉ cho phép kết nối TCP bình thường.
Đảm bảo UFW đã bật và cho phép truy cập SSH:
sudo ufw limit 22/tcp
sudo ufw enable
Gói tin không hợp lệ là những gói không bắt đầu chỉ với cờ SYN duy nhất.
Trong handshake TCP chuẩn, mọi kết nối mới phải bắt đầu bằng gói SYN.
Nếu gói TCP mới bắt đầu với cờ khác hoặc tổ hợp cờ bất thường (ví dụ do công cụ quét cổng như Nmap tạo ra) thì cần chặn.
Thêm đoạn sau vào cuối file before.rules và before6.rules ngay sau dòng cuối cùng COMMIT:
*mangle
:PREROUTING ACCEPT [0:0]
-A PREROUTING -m conntrack --ctstate INVALID -j DROP
-A PREROUTING -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j DROP
COMMIT
Reload UFW:
sudo ufw reload
Giải thích:
- Dòng đầu tiên thả các gói tin bị đánh dấu là
INVALID. - Dòng thứ hai thả các gói TCP mới (
NEW) mà không có đúng cờ SYN đơn thuần.
Các quy tắc này nằm trong bảng mangle ở chuỗi PREROUTING, tức xử lý ngay khi gói đến server nhằm giảm tải cho firewall về sau.
Quy tắc chống SYN Flood
Giả sử bạn đã bật firewall chỉ cho phép SSH và đã thêm quy tắc chặn gói tin không hợp lệ như trên.
Quy tắc limit của UFW cho SSH đủ bảo vệ cổng 22 khỏi SYN flood rồi.
Dưới đây là các cách cấu hình chống tấn công SYN flood cho bất kỳ dịch vụ TCP nào (ví dụ HTTP cổng 80).
Cách 1
Thêm đoạn sau vào cuối file before.rules, trước dòng cuối cùng COMMIT:
-A ufw-before-input -p tcp --syn --dport 80 -m conntrack --ctstate NEW -m limit --limit 10/second --limit-burst 20 -j ACCEPT
-A ufw-before-input -p tcp --syn --dport 80 -m conntrack --ctstate NEW -m limit --limit 10/second --limit-burst 20 -j LOG --log-prefix "[UFW SYN Flood Detected] "
-A ufw-before-input -p tcp --syn --dport 80 -j DROP
Giải thích:
- Cho phép tối đa 10 gói SYN/giây từ mỗi IP với đợt bùng phát đầu là 20 gói.
- Ghi lại (log) những gói vượt quá giới hạn với tiền tố
[UFW SYN Flood Detected]. - Thả (drop) những gói vượt quá giới hạn đó.
Quy tắc áp dụng trên chuỗi ufw-before-input, xử lý trước các quy tắc người dùng. Tương tự áp dụng cho IPv6 trong file before6.rules nhưng đổi chuỗi thành ufw6-before-input.
Sau khi sửa, reload UFW lại.
Khi giả lập tấn công bằng hping3, bạn sẽ thấy log liên tục xuất hiện cảnh báo và server vẫn hoạt động ổn định.
Cách 2
Nhược điểm của cách 1 là giới hạn toàn cục, tức nếu một IP tấn công thì tất cả IP khác cũng bị ảnh hưởng vì giới hạn chung.
Cách tốt hơn là giới hạn riêng biệt theo từng IP bằng module hashlimit.
Thay thế đoạn cũ bằng đoạn sau:
-A ufw-before-input -p tcp --syn --dport 80 -m conntrack --ctstate NEW -m hashlimit --hashlimit-name http_limit --hashlimit-above 10/second --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-srcmask 32 -j DROP
-A ufw-before-input -p tcp --syn --dport 80 -m conntrack --ctstate NEW -m hashlimit --hashlimit-name http_limit --hashlimit-above 10/second --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-srcmask 32 -j LOG --log-prefix "[UFW SYN Flood Detected] "
-A ufw-before-input -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
Giải thích thêm:
- Giới hạn áp dụng riêng cho từng địa chỉ IP nguồn (
srcip) với subnet mask /32 (IP đơn lẻ). - Nếu muốn nhóm IP theo subnet có thể giảm mask ví dụ
/24.
Khi thử lại, tôi vẫn truy cập được trang mặc định NGINX trong lúc tấn công giả lập.
Cách 3
Muốn duy trì danh sách đen IP đã từng tấn công để chặn lâu dài hơn, tôi kết hợp module recent với hashlimit.
Các quy tắc hiện tại:
-A ufw-before-input -p tcp --syn --dport 80 -m conntrack --ctstate NEW -m hashlimit --hashlimit-name http_limit --hashlimit-above 10/second --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-srcmask 32 -m recent --name blacklist --set --rsource -j DROP
-A ufw-before-input -p tcp --syn --dport 80 -m conntrack --ctstate NEW -m hashlimit --hashlimit-name http_limit --hashlimit-above 10/second --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-srcmask 32 -j LOG --log-prefix "[UFW SYN Flood Detected] "
-A ufw-before-input -m recent --name blacklist --rcheck --seconds 300 --hitcount 1 --rsource -j DROP
-A ufw-before-input -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
Giải thích:
- Nếu IP vượt quá giới hạn, nó được thêm vào danh sách đen (
blacklist) và bị chặn. - Danh sách đen lưu trong bộ nhớ nên mất sau reboot.
- IP trong blacklist bị chặn trong vòng 5 phút.
- Nếu IP dừng gửi gói vượt mức thì sau thời gian timeout sẽ được bỏ blacklist.
- Nếu IP tiếp tục gửi nhiều sẽ bị giữ blacklist vô thời hạn.
Nếu bạn bị blacklist nhầm, chỉ cần đợi timeout hoặc dùng Fail2ban để quản lý tốt hơn (xem phần dưới).
Giải pháp cuối cùng
Mục tiêu: bảo vệ cả cổng HTTP (80) và HTTPS (443) khỏi SYN flood đồng thời dùng Fail2ban để quản lý blacklist IP hiệu quả trên toàn bộ cổng.
Fail2ban giúp duy trì danh sách đen bền vững qua reboot và linh hoạt hơn so với module recent.
Cài đặt Fail2ban
sudo apt install fail2ban
Tạo filter mới trong /etc/fail2ban/filter.d/synflood.conf với nội dung:
[Definition]
failregex = .*UFW SYN Flood Detected.*SRC=<HOST>.*DPT=\d+.*
ignoreregex =
Tạo bản sao cấu hình jail:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Chỉnh sửa file /etc/fail2ban/jail.local, thêm:
[synflood]
enabled = true
filter = synflood
action = iptables[type=allports, name=synflood, chain=fail2ban, protocol=tcp]
logpath = /var/log/syslog
maxretry = 5
findtime = 600
bantime = 86400
Giải thích:
- Jail “synflood” kích hoạt.
- Nếu IP xuất hiện trong log từ khóa
[UFW SYN Flood Detected]quá 5 lần trong vòng 10 phút sẽ bị chặn toàn bộ cổng trong một ngày. - Dùng iptables chặn thay vì UFW để tránh xung đột thứ tự xử lý quy tắc.
Thêm chuỗi mới vào iptables
Mở file before.rules, thêm hai chuỗi dưới dòng “# End required lines”:
:SYN_FLOOD_PROTECTION - [0:0]
:fail2ban - [0:0]
Sửa quy tắc:
-A ufw-before-input -j fail2ban
# (fail2ban sẽ thêm luật chặn IP ở đây)
-A fail2ban -j RETURN
-A ufw-before-input -p tcp --syn --dport 80 -j SYN_FLOOD_PROTECTION
-A ufw-before-input -p tcp --syn --dport 443 -j SYN_FLOOD_PROTECTION
-A SYN_FLOOD_PROTECTION -p tcp --syn --dport 80 -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_limit \
--hashlimit-above 10/second --hashlimit-burst 20 \
--hashlimit-mode srcip --hashlimit-srcmask 32 -j DROP
-A SYN_FLOOD_PROTECTION -p tcp --syn --dport 80 -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_limit \
--hashlimit-above 10/second --hashlimit-burst 20 \
--hashlimit-mode srcip --hashlimit-srcmask 32 -j LOG \
--log-prefix "[UFW SYN Flood Detected] "
-A SYN_FLOOD_PROTECTION -p tcp --syn --dport 443 -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_limit \
--hashlimit-above 10/second --hashlimit-burst 20 \
--hashlimit-mode srcip --hashlimit-srcmask 32 -j DROP
-A SYN_FLOOD_PROTECTION -p tcp --syn --dport 443 -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-name http_limit \
--hashlimit-above 10/second --hashlimit-burst 20 \
--hashlimit-mode srcip --hashlimit-srcmask 32 -j LOG \
--log-prefix "[UFW SYN Flood Detected] "
-A SYN_FLOOD_PROTECTION -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
-A SYN_FLOOD_PROTECTION -p tcp --syn --dport 443 -m conntrack --ctstate NEW -j ACCEPT
Giải thích:
- Lưu lượng đầu vào đầu tiên đi qua chuỗi fail2ban để chặn IP blacklist.
- Sau đó về chuỗi SYN_FLOOD_PROTECTION xử lý giới hạn tốc độ.
- Cuối cùng cho phép các kết nối hợp lệ vượt qua.
Cũng áp dụng tương tự cho IPv6 trong file before6.rules, đổi tên chuỗi tương ứng thành ufw6-before-input.
Reload UFW:
sudo ufw reload
Khởi động lại Fail2ban:
sudo systemctl restart fail2ban
Kiểm tra trạng thái jail synflood:
sudo fail2ban-client status synflood
Xem danh sách IP đang bị chặn trong chuỗi fail2ban iptables:
sudo iptables -L fail2ban -v -n
Xem chi tiết luật chặn của Fail2ban tại chuỗi tương ứng như f2b-synflood:
sudo iptables -L f2b-synflood -v -n
Nếu khởi tạo một cuộc tấn công giả lập bằng hping3, Fail2ban sẽ tự động phát hiện và chặn IP đó truy cập tất cả cổng trên server.
Muốn bỏ chặn IP:
sudo fail2ban-client set synflood unbanip <địa_chỉ_IP>
Lời khuyên cuối cùng
Bạn nên điều chỉnh các thông số giới hạn phù hợp với từng môi trường vận hành.
Điểm mạnh giải pháp này là Fail2ban dựa vào log nên rất dễ mở rộng cho nhiều dịch vụ khác nhau chỉ cần dùng chung tiền tố log tương tự mà không phải chỉnh cấu hình phức tạp nhiều lần.









