Fail2ban được cài đầu tiên và thường cũng dừng lại ở đó: gói đã cài, dịch vụ đang chạy, sshd có vẻ đã được che chắn. Sáu tháng sau mới lộ ra rằng jail đang đọc một tệp không hề tồn tại trên hệ thống này, còn tất cả phần còn lại — thư, bảng điều khiển, biểu mẫu đăng nhập của trang web — chưa bao giờ được che chắn cả.

Hãy xem trên một VPS thông thường có trang web thì nên bật gì, nên đặt những con số nào, và làm sao chắc chắn rằng jail đang hoạt động chứ không chỉ hiện diện trong tệp cấu hình.

Trước hết hãy kiểm tra xem sshd có bắt được gì không

Một lệnh:

sudo fail2ban-client status sshd

Kết quả có các dòng Currently failed, Total failedTotal banned. Nếu trên một máy chủ đã ở trên Internet ít nhất một ngày mà Total failed bằng không, thì jail không hoạt động. Hãy đối chiếu với thực tế:

sudo lastb | wc -l

Hàng nghìn lần thử thất bại trong lastb đối lại với những con số không trong Fail2ban chỉ có nghĩa duy nhất: bộ lọc đang nhìn nhầm chỗ.

Nguyên nhân phổ biến nhất là Debian 12. Nó không còn cài rsyslog theo mặc định, tệp /var/log/auth.log đơn giản là không tồn tại, còn jail sshd tiêu chuẩn lại được cấu hình để đọc đúng tệp đó. Không có lỗi nào báo về chuyện này: dịch vụ khởi động, trạng thái hiển thị, các bộ đếm vẫn bằng không. Cách sửa là chuyển sang nhật ký của systemd:

[sshd]
enabled = true
backend = systemd

Lựa chọn khác là mang rsyslog trở lại như một gói, nếu tệp auth.log dạng văn bản thuần cần cho các công cụ khác. Ubuntu 24.04 cũng hành xử y hệt.

Đặt cấu hình của mình ở đâu

Đừng động vào /etc/fail2ban/jail.conf: khi cập nhật gói nó bị ghi đè, và mọi chỉnh sửa làm ở đó một ngày nào đó sẽ lặng lẽ biến mất. Cấu hình của riêng bạn đi vào /etc/fail2ban/jail.local — tệp này được đọc sau cùng và có trọng số cao hơn tệp chung.

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.25
bantime  = 1h
findtime = 10m
maxretry = 5
backend  = systemd

ignoreip với địa chỉ của chính bạn không phải xa xỉ mà là bảo hiểm: tự khóa mình ra ngoài vì một lỗi gõ dễ hơn ta tưởng. Nếu không có địa chỉ tĩnh, hãy giữ một lối vào thứ hai ngoài SSH — console của nhà cung cấp hoặc VNC.

Jail làm thay đổi bức tranh: recidive

Một jail thông thường có trí nhớ ngắn: năm lần thử trong mười phút, cấm một giờ, rồi một giờ sau mọi thứ bắt đầu lại. Bot sống khỏe với điều đó và sẽ quay lại cả ngày mai lẫn ngày kia. recidive bịt đúng khoảng trống ấy: nó không đọc nhật ký hệ thống mà đọc nhật ký của chính Fail2ban, tức là nó cấm kẻ mà Fail2ban đã cấm rồi.

[recidive]
enabled  = true
bantime  = 1w
findtime = 1d
maxretry = 5

Hãy đọc thế này: «bị cấm năm lần trong một ngày — biến mất một tuần». Jail này cần tệp /var/log/fail2ban.log, nên nếu bạn đã chuyển nhật ký của chính Fail2ban sang syslog thì recidive cũng sẽ cần backend = systemd.

Trên thực tế hiệu quả của riêng jail này thường thấy rõ hơn việc tinh chỉnh tất cả những cái còn lại: những kẻ thường xuyên rơi rụng đi và trong nhật ký chỉ còn lại nền nhiễu mới.

Còn nên bật gì khi máy chủ có trang web

Theo thứ tự hữu ích giảm dần:

  • nginx-http-auth hoặc apache-auth — dò mật khẩu ở xác thực cơ bản. Cần thiết nếu khu vực quản trị hoặc trang staging nằm sau mật khẩu của máy chủ web;
  • nginx-botsearch — dò tìm các đường dẫn quen thuộc: /wp-login.php, /phpmyadmin, /.env. Đó không phải đột nhập mà là do thám, và nó đi trước tất cả những thứ khác;
  • nginx-limit-req — chỉ hoạt động nếu trong chính Nginx có định nghĩa limit_req_zone; không có nó thì jail được bật mà vô dụng;
  • postfix-sasldovecot — bắt buộc nếu bạn tự chạy thư. Việc dò mật khẩu hộp thư diễn ra liên tục và thường chẳng ai theo dõi.
[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log

Biểu mẫu đăng nhập của chính trang web là một câu chuyện riêng. Ứng dụng không có nhật ký đăng nhập thất bại của riêng mình, còn trong access.log một lần thử thất bại trông như một POST bình thường với mã 200 hoặc 302 — không thể phân biệt với lần thành công bằng bất kỳ bộ lọc chung nào. Có hai cách: hoặc để ứng dụng ghi các lần thất bại vào syslog (đa số hệ quản trị nội dung đều có plugin cho việc này), hoặc giới hạn tần suất yêu cầu tới trang đăng nhập. Cách thứ hai là bộ giới hạn chứ không phải bộ phát hiện, và biết trước điều đó thì tốt hơn.

Những con số

bantime = 10m chính là giá trị mặc định khiến người ta gạt bỏ Fail2ban như thứ vô dụng: mười phút là đủ để bot quay lại. Một giờ cho lần cấm đầu cộng với recidive một tuần hoạt động tốt hơn nhiều so với cấm vĩnh viễn, thứ theo thời gian biến thành một danh sách quy tắc dài dằng dặc.

maxretry = 3 cho SSH là cách đáng tin cậy để tự khóa mình ra ngoài. Năm lần thử trong mười phút cũng cắt được việc dò mật khẩu tốt chẳng kém.

Việc dò chậm — một lần thử mỗi năm phút — sẽ không bao giờ rơi vào findtime. Đó không phải lý do để kéo cửa sổ ra thành một ngày: bạn sẽ nhận về những lệnh cấm sai với chính đồng nghiệp của mình. Cái có tác dụng với việc dò chậm không phải là ngưỡng mà là tắt xác thực bằng mật khẩu.

Hãy chắc chắn lệnh cấm chạm tới gói tin

Fail2ban chỉ gọi một lệnh bên ngoài. Nếu banaction không khớp với thứ thực sự lọc lưu lượng, nhật ký sẽ đầy những dòng Ban 198.51.100.7 đầy hớn hở trong khi gói tin vẫn tiếp tục đến. Debian 12 mặc định dùng nftables, và khi UFW đang bật thì lựa chọn đúng là banaction = ufw. Để kiểm tra:

sudo nft list ruleset | grep -c f2b
sudo iptables -S | grep f2b

Ít nhất một trong hai phải hiển thị quy tắc. Còn chính bộ lọc thì có thể thử mà không cần chờ một cuộc tấn công:

sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf

Cuối kết quả có ghi bao nhiêu dòng đã khớp. Số không nghĩa là bộ lọc và nhật ký không gặp nhau, và chẳng có ý nghĩa gì để cấu hình tiếp.

Những gì Fail2ban không làm

Nó không bảo vệ trước việc dò mật khẩu phân tán: một nghìn địa chỉ mỗi cái thử một lần sẽ không bao giờ chạm ngưỡng với bất kỳ cấu hình nào. Nó không loại bỏ nguyên nhân — một địa chỉ bị cấm không hủy bỏ một mật khẩu yếu. Và nó chẳng biết gì về danh tiếng: địa chỉ hôm qua dành cả ngày đột nhập máy chủ của người khác vẫn sạch trong mắt nó cho tới khi bắt đầu với bạn. Từ đó mà có sự kết hợp dùng trong thực tế: khóa thay cho mật khẩu, Fail2ban như bộ giới hạn tiếng ồn, và danh sách chặn chung (CrowdSec) như tri thức từ kinh nghiệm của người khác.

Một vấn đề riêng là tất cả những thứ này thỉnh thoảng cần có người nhìn vào. Chẳng ai gõ fail2ban-client status cho từng jail suốt nhiều tuần liền, còn số lệnh cấm tăng lên chỉ được để ý khi có gì đó đã hỏng. Trên các trang demo bên dưới, cùng dữ liệu ấy nằm trên một trang: danh sách jail, ai đang bị cấm lúc này, và các lần thử đến từ đâu.