Cơn ác mộng rà log lúc 2 giờ sáng
2 giờ sáng, chuông PagerDuty réo inh ỏi. Màn hình Grafana đỏ rực: CPU máy chủ chạm trần 100%, hơn 45.000 request rác dội thẳng vào endpoint /api/v1/search chỉ trong 3 phút. Mở access log của Nginx, đập vào mắt mình là cả hàng dài payload khai thác quen thuộc:
tail -f /var/log/nginx/access.log | grep -E "UNION|SELECT|<script>"
Backend Node.js cạn sạch connection pool vào PostgreSQL. IPTables hay Firewalld ở Layer 3/4 hoàn toàn vô hiệu. Mọi gói tin đều đi qua cổng 443 hợp lệ với SSL handshake mượt mà. Lúc này, hệ thống cần một bộ lọc ở tầng ứng dụng (Layer 7) để bóc tách URI, query string và request body trước khi đẩy tiếp vào backend. Đó là lý do bạn cần dựng ModSecurity v3 cùng bộ quy tắc OWASP Core Rule Set (CRS).
ModSecurity v3 và OWASP CRS kết hợp như thế nào?
Trước khi gõ lệnh, hãy làm rõ vai trò của từng thành phần:
- ModSecurity v3 (libmodsecurity): Đây là engine phân tích traffic độc lập viết bằng C++. Khác với bản v2 gắn chặt vào Apache, bản v3 chạy dạng thư viện rời và kết nối với Nginx qua dynamic module
modsecurity-nginx. Nó chịu trách nhiệm parse gói tin HTTP, đọc headers, buffer body và chạy các rule kiểm tra. - OWASP Core Rule Set (CRS): Đây là bộ luật bảo mật mã nguồn mở được cộng đồng cập nhật liên tục. CRS nhận diện hầu hết các lỗ hổng thuộc OWASP Top 10: SQL Injection, Cross-Site Scripting (XSS), Local File Inclusion (LFI) hay Scanner Detection. CRS vận hành theo cơ chế chấm điểm bất thường (Anomaly Scoring). Mỗi request khả nghi sẽ bị cộng điểm vi phạm. Nếu tổng điểm vượt ngưỡng (mặc định là 5), Nginx sẽ lập tức ngắt kết nối với mã lỗi 403 Forbidden.
Triển khai trên CentOS Stream 9
Các bước dưới đây thực hiện với quyền root hoặc user có quyền sudo.
Bước 1: Bật repo EPEL và cài đặt package phụ trợ
CentOS Stream 9 cần repo EPEL và CRB (CodeReady Builder) để kéo đủ thư viện phát triển:
dnf install -y epel-release
dnf config-manager --set-enabled crb
dnf update -y
dnf install -y gcc-c++ make automake autoconf libtool libxml2-devel \
pcre2-devel libcurl-devel yajl-devel geoip-devel zlib-devel git
Bước 2: Cài Nginx và module ModSecurity
Kho EPEL 9 đã đóng gói sẵn Nginx cùng module connector tương thích. Bạn không cần tốn 20 phút biên dịch lại toàn bộ Nginx từ source:
dnf install -y nginx nginx-mod-modsecurity
systemctl enable --now nginx
Xác minh Nginx đã nhận module dynamic:
nginx -V 2>&1 | grep -o "--with-compat"
Bước 3: Chuẩn bị file cấu hình ModSecurity
Tải file cấu hình khuyến nghị từ SpiderLabs về thư mục cấu hình Nginx:
mkdir -p /etc/nginx/modsec
cd /etc/nginx/modsec
curl -fsSL https://raw.githubusercontent.com/owasp-modsecurity/ModSecurity/v3/master/modsecurity.conf-recommended -o modsecurity.conf
curl -fsSL https://raw.githubusercontent.com/owasp-modsecurity/ModSecurity/v3/master/unicode.mapping -o unicode.mapping
Chỉ định đường dẫn audit log và tăng giới hạn request body lên 20MB để tránh drop nhầm file upload của người dùng:
sed -i 's|SecAuditLog /var/log/modsec_audit.log|SecAuditLog /var/log/nginx/modsec_audit.log|' /etc/nginx/modsec/modsecurity.conf
sed -i 's/SecRequestBodyLimit 13107200/SecRequestBodyLimit 20971520/' /etc/nginx/modsec/modsecurity.conf
Ban đầu, hãy giữ nguyên dòng SecRuleEngine DetectionOnly. Thiết lập này cho phép WAF ghi nhận vi phạm vào log mà chưa chặn traffic, tránh làm đứt đoạn dịch vụ của khách hàng.
Bước 4: Nạp bộ luật OWASP CRS v4
Tải bản release ổn định của CRS v4 từ GitHub:
cd /etc/nginx/modsec
git clone --branch v4.0.0 https://github.com/coreruleset/coreruleset.git owasp-crs
cd owasp-crs
cp crs-setup.conf.example crs-setup.conf
Tạo file nạp tổng hợp /etc/nginx/modsec/main.conf để Nginx tải toàn bộ rule theo thứ tự:
cat << 'EOF' > /etc/nginx/modsec/main.conf
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/owasp-crs/crs-setup.conf
Include /etc/nginx/modsec/owasp-crs/rules/*.conf
EOF
Bước 5: Kích hoạt WAF trên Virtual Host Nginx
Mở file cấu hình vhost, ví dụ /etc/nginx/conf.d/default.conf, rồi thêm chỉ thị ModSecurity vào block server:
server {
listen 80;
server_name example.com;
# Bật ModSecurity
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
Kiểm tra cú pháp cấu hình:
nginx -t
Khi màn hình hiển thị syntax is ok, reload Nginx:
systemctl reload nginx
Bước 6: Test thực tế và đọc audit log
Gửi một request hợp lệ để kiểm tra kết nối:
curl -I http://localhost/
Server phản hồi HTTP/1.1 200 OK. Tiếp theo, thử gửi một payload SQL Injection kinh điển:
curl -I "http://localhost/?id=1%27%20OR%20%271%27=%271"
Mở file audit log để xem chi tiết cách engine đánh giá request này:
tail -n 35 /var/log/nginx/modsec_audit.log
Trong log, bạn sẽ thấy rule ID 942100 (SQL Injection Detected via libinjection) kích hoạt và cộng 5 điểm vi phạm. Khi hệ thống đã chạy ổn định và bạn đã whitelist các request đặc thù, hãy chuyển sang chế độ chặn thật bằng cách sửa dòng sau trong /etc/nginx/modsec/modsecurity.conf:
SecRuleEngine On
Reload lại Nginx. Chạy lại lệnh curl chứa payload SQLi ở trên, server sẽ trả về ngay mã lỗi HTTP/1.1 403 Forbidden.
Kinh nghiệm vận hành thực tế
Đừng bật SecRuleEngine On ngay trên production nếu bạn chưa chạy thử nghiệm. Hãy giữ chế độ DetectionOnly tối thiểu 48 đến 72 giờ. Lọc file modsec_audit.log để tìm các request hợp lệ bị chấm điểm nhầm (False Positive) — điển hình là payload JSON chứa ký tự đặc biệt hoặc các lệnh Markdown từ CMS.
Khi gặp báo động nhầm, hãy dùng chỉ thị SecRuleRemoveById trong file cấu hình riêng thay vì tắt bỏ toàn bộ rule file. Cách tiếp cận này giữ cho hệ thống an toàn mà không làm gián đoạn trải nghiệm của người dùng thật.
