ติดตั้ง ModSecurity WAF บน Nginx VPS

ติดตั้ง ModSecurity WAF บน Nginx VPS

มิถุนายน 2026 · อ่าน 9 นาที

ModSecurity คือ Web Application Firewall (WAF) ที่แรงที่สุดสำหรับ Nginx — ป้องกัน SQL injection, XSS, Remote Code Execution และการโจมตีเว็บอื่นๆ โดยใช้ OWASP Core Rule Set (CRS) ที่ทีม OWASP ดูแลและอัปเดตอย่างต่อเนื่อง บทความนี้สอนติดตั้ง ModSecurity บน Nginx compile จาก source, ตั้ง OWASP CRS ให้ทำงาน 2 mode (detection + prevention) และสาธิตการ test ว่าบล็อก SQL injection และ XSS ได้จริง

ความเข้าใจพื้นฐาน WAF vs Firewall

Firewall ตรวจสอบที่ layer 3/4 (IP, port) ส่วน WAF ตรวจสอบที่ layer 7 (HTTP request body) — เห็น SQL injection statement ได้เพราะอ่านเนื้อหา HTTP แล้วแยกวิเคราะห์ ModSecurity ทำงาน 2 mode:

ติดตั้ง Nginx ModSecurity Module

Nginx ไม่รองรับ dynamic module สำหรับ ModSecurity ต่างจาก Apache จึงต้อง compile Nginx เองพร้อม ModSecurity module:

# อัปเดท package
apt update && apt upgrade -y

# ติดตั้ง dependencies
apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev libgd-dev libgeoip-dev libjemalloc-dev wget curl git

# ดาวน์โหลด Nginx source
cd /tmp
wget http://nginx.org/download/nginx-1.26.0.tar.gz
tar xzf nginx-1.26.0.tar.gz

# ดาวน์โหลด ModSecurity connector สำหรับ Nginx
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git

# ดาวน์โหลด ModSecurity เอง (standalone library)
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity.git

# Build ModSecurity library
cd ModSecurity
./build.sh
./configure --prefix=/usr/local/modsecurity
make && make install

# ตรวจ ModSecurity library ติดตั้งสำเร็จ
ls -la /usr/local/modsecurity/lib/

# กลับไป compile Nginx พร้อม ModSecurity module
cd /tmp/nginx-1.26.0
./configure \
  --prefix=/etc/nginx \
  --sbin-path=/usr/sbin/nginx \
  --modules-path=/usr/lib64/nginx/modules \
  --conf-path=/etc/nginx/nginx.conf \
  --error-log-path=/var/log/nginx/error.log \
  --http-log-path=/var/log/nginx/access.log \
  --pid-path=/var/run/nginx.pid \
  --lock-path=/var/run/nginx.lock \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-http_realip_module \
  --with-http_gzip_static_module \
  --with-http_secure_link_module \
  --with-http_auth_request_module \
  --add-dynamic-module=/tmp/ModSecurity-nginx

make && make install

# Verify Nginx build
nginx -v
nginx -t

ติดตั้ง OWASP Core Rule Set (CRS)

CRS คือชุด rules ของ OWASP ที่ตรวจจับการโจมตีทั่วไป SQL injection, XSS, Remote File Inclusion เป็นต้น ปล่อยให้ลูกค้าสามารถปรับเพิ่มเติมตามความต้องการ:

# ดาวน์โหลด OWASP CRS (Community Rules)
cd /opt
git clone https://github.com/coreruleset/coreruleset.git crs

# ไป /opt/crs
cd crs

# Copy config template เป็น config ที่ใช้จริง
cp crs-setup.conf.example crs-setup.conf

# Copy rules ที่ active
cp rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
cp rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf

# ตรวจ CRS ติดตั้งสำเร็จ
ls -la /opt/crs/rules/ | head -20

ตั้ง ModSecurity ใน Nginx Config

เปิดไฟล์ nginx.conf แล้วเพิ่ม ModSecurity directive:

sudo nano /etc/nginx/nginx.conf

# ใน http block เพิ่มบรรทัดต่อไปนี้ (ก่อน "include /etc/nginx/sites-enabled/*")
load_module modules/ngx_http_modsecurity_module.so;

http {
    # ... อื่นๆ ...

    # ModSecurity setup
    modsecurity on;
    modsecurity_rules_file /opt/crs/crs-setup.conf;
    modsecurity_rules_file /opt/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf;
    modsecurity_rules_file /opt/crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf;

    # Include ทุก .conf ใน rules/
    include /opt/crs/rules/*.conf;

    # ... server blocks อื่นๆ ...
    include /etc/nginx/sites-enabled/*;
}

สร้าง main config สำหรับ ModSecurity (ใน /opt/crs/):

sudo cat > /opt/crs/modsecurity.conf << 'EOF'
# ModSecurity setup (แล้ว default)
SecRuleEngine DetectionOnly

# ตั้ง audit log
SecAuditEngine On
SecAuditLog /var/log/modsecurity/audit.log
SecAuditLogFormat JSON
SecAuditLogType Concurrent

# Set log file
SecDebugLog /var/log/modsecurity/debug.log
SecDebugLogLevel 3

# ความสูงของ HTTP body ที่ ModSecurity จะสแกน
SecRequestBodyLimit 13107200
SecRequestBodyInMemoryLimit 131072

# ความสูง response body
SecResponseBodyLimit 1048576

# Disable for CONNECT requests (VPN/tunnel)
SecAllowList 2000 id:2000 phase:1 t:none nolog noauditlog "CONNECT" "@rx ^CONNECT$"
EOF

# สร้าง directory log
mkdir -p /var/log/modsecurity
chmod 755 /var/log/modsecurity

# Test Nginx config
sudo nginx -t

เปลี่ยนจาก Detection Mode เป็น Prevention Mode

เมื่อมั่นใจ rules ไม่บล็อก legitimate traffic แล้ว เปลี่ยนเป็น prevention mode:

# แก้ไข modsecurity.conf
sudo sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /opt/crs/modsecurity.conf

# Reload Nginx
sudo nginx -t && sudo systemctl reload nginx

# ตรวจ log ว่ามี error ไหม
tail -f /var/log/nginx/error.log

Test ModSecurity ว่า Block SQL Injection และ XSS ได้

เขียน rule test เพื่อตรวจ ModSecurity ป้องกันได้:

# Test SQL injection — ตัด CRS ออกชั่วคราว และใช้ test rule อย่างง่าย
cat > /opt/crs/test-rules.conf << 'EOF'
# Simple test rules
SecRule ARGS "@rx (?i:union.*select)" "id:1000,phase:2,deny,log,msg:'SQL Injection attempt'"
SecRule ARGS "@rx (?i:alert('xss')"
# ต้องได้ HTTP 403 Forbidden

# ดู log
sudo tail -f /var/log/modsecurity/audit.log

ตั้ง ModSecurity ต่อ Virtual Host เฉพาะ

ถ้าต้องการเปิด ModSecurity เพียง vhost บางตัว ให้ตั้ง detection mode ท่องพิ้นกว่าแล้ว override ใน location block:

sudo cat > /etc/nginx/sites-available/myapp << 'EOF'
server {
    listen 80;
    server_name myapp.com;

    # เปิด ModSecurity สำหรับ vhost นี้
    modsecurity on;
    modsecurity_rules_file /opt/crs/crs-setup.conf;
    modsecurity_rules_file /opt/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Exclude rules บาง endpoint (เช่น API ที่合法ส่ง payload ใหญ่)
    location /api/upload {
        modsecurity_rules "SecRequestBodyLimit 52428800";  # 50 MB
        proxy_pass http://127.0.0.1:3000;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Exclude Rules ถ้า False Positive

ถ้า ModSecurity บล็อก legitimate request ให้ดู rule ID แล้ว exclude มัน:

# ดู audit log เพื่อหา rule ID ที่บล็อก
sudo tail -f /var/log/modsecurity/audit.log | grep "id:"

# ตัวอย่าง จาก CRS rule 930100 ถูก trigger เพราะ PHP code ในคำค้นหา
# Exclude rule 930100 สำหรับ /admin path
cat >> /opt/crs/modsecurity.conf << 'EOF'

# Whitelist rules ที่ false positive
SecRule REQUEST_URI "@beginsWith /admin/upload" \
  "id:10000,phase:1,nolog,pass,skipAfter:END_WHITELIST"

# หรือ disable specific rule globally
SecRuleRemoveById 930100

SecMarker "END_WHITELIST"
EOF

# Reload Nginx
sudo systemctl reload nginx

ตรวจสอบว่า ModSecurity ทำงานถูกต้อง

# ตรวจ Nginx load module สำเร็จ
sudo nginx -t
# ต้องเห็น "nginx: configuration file /etc/nginx/nginx.conf test is successful"

# ดู Nginx process ว่าโหลด modsecurity module
ps aux | grep nginx

# ตรวจ ModSecurity status log
sudo tail -20 /var/log/nginx/error.log | grep -i modsecurity

# ดู audit log รายละเอียด
sudo tail -50 /var/log/modsecurity/audit.log | python3 -m json.tool

# Test request ปกติว่า ผ่านได้ (200 OK)
curl -v "http://127.0.0.1/" --output /dev/null -s -w "%{http_code}\n"
# ต้องได้ 200 หรือ 301/302 ถ้ามี redirect

# Test request ที่มี malicious pattern
curl -v "http://127.0.0.1/?id=1' or '1'='1" 2>&1 | grep -i "403\|denied"
Tip: ถ้า ModSecurity เริ่มบล็อก legitimate traffic เมื่อเปิด prevention mode ให้กลับมา detection mode หา rule ID ที่false positive จาก audit.log แล้ว exclude มันไปก่อน — ห้ามปิด WAF ทั้งหมด เพราะด้อยการป้องกัน

แก้ปัญหาที่พบบ่อย

Error: "nginx: [emerg] module not found"

ModSecurity module ไม่ compile สำเร็จหรือ Nginx หา .so file ไม่เจอ

# ตรวจว่า .so file มีจริง
ls -la /usr/lib64/nginx/modules/ngx_http_modsecurity_module.so
ls -la /etc/nginx/modules/ngx_http_modsecurity_module.so

# ถ้ามี .so แค่ path ผิด ให้แก้ nginx.conf
sudo nano /etc/nginx/nginx.conf
# ตรวจบรรทัด: load_module modules/ngx_http_modsecurity_module.so;
# ที่ prefix /etc/nginx จึง module จะหาจาก /etc/nginx/modules/

# ถ้าไม่มี .so file ต้อง recompile Nginx
cd /tmp/nginx-1.26.0
./configure --add-dynamic-module=/tmp/ModSecurity-nginx ... (เพิ่มเท่านี้)
make
# ตัด make install เพราะเปลี่ยน .so แล้ว คัดลอกแค่ .so
sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/

Error: "can't allocate memory" ในข้าง ModSecurity

ModSecurity กำลังสแกน request ขนาดใหญ่และหมดพื้นที่ buffer

# ลด SecRequestBodyInMemoryLimit ลง
sudo nano /opt/crs/modsecurity.conf
# แก้:
SecRequestBodyInMemoryLimit 65536     # ลดจาก 131072

# หรือเพิ่ม RAM VPS ของคุณ แล้วเพิ่ม limit ให้มากขึ้น
SecRequestBodyInMemoryLimit 262144    # 256 KB

# Restart services
sudo systemctl restart nginx

ERROR 403 Forbidden ขึ้นบน legitimate request

WAF บล็อก legitimate request — ต้อง whitelist rules นั้น

# ดูว่า rule ไหนบล็อก (ใน audit log)
sudo grep "\"severity\":\"CRITICAL\"" /var/log/modsecurity/audit.log | tail -5

# หา rule ID ที่บล็อก เช่น id:930100
# ใน modsecurity.conf disable rule นั้น
echo "SecRuleRemoveById 930100" | sudo tee -a /opt/crs/modsecurity.conf

# หรือ disable rule สำหรับ path นั้น
echo "SecRule REQUEST_URI \"@beginsWith /api\" \"id:10001,phase:1,nolog,pass,skipAfter:SKIP_API\"" | sudo tee -a /opt/crs/modsecurity.conf
echo "SecMarker \"SKIP_API\"" | sudo tee -a /opt/crs/modsecurity.conf

# Reload
sudo systemctl reload nginx

# Test อีกครั้ง
curl -v "http://127.0.0.1/path/to/resource"

ModSecurity สาหรับ HTTPS แล้วบล็อกทั้งหมด

การ decrypt HTTPS ต้อง certificate trusty หรือ ModSecurity เห็น SSL error

# ตรวจ error log
sudo tail -50 /var/log/nginx/error.log | grep -i ssl

# ถ้า SSL certificate invalid ให้ renew
sudo certbot renew --force-renewal

# แก้ proxy_pass กำหนด HTTPS backend
location / {
    proxy_pass https://backend.example.com:443;  # ใช้ HTTPS
    proxy_ssl_verify off;                         # ถ้า self-signed
    proxy_ssl_trusted_certificate /etc/ssl/certs/ca-bundle.crt;
}

คำถามที่พบบ่อย

ModSecurity กิน CPU/Memory เท่าไหร?

ModSecurity เมื่อสแกน request ขนาดใหญ่จะกิน CPU สูง แต่เฉลี่ยแล้วกิน ~2-5% ต่อ request สำหรับ detection mode ดีกว่า prevention mode เพราะไม่บล็อก จึงไม่ต้องประเมิน request ซ้ำ ถ้า VPS มี CPU 2 core แนะนำใช้ detection mode บน production ก่อนแล้ว scale infrastructure ถ้าต้องใช้ prevention

ModSecurity รองรับ HTTP/3 ได้ไหม?

ตัว ModSecurity module ของ Nginx เฉพาะ HTTP/1.1 และ HTTP/2 ทำงาน HTTP/3 (QUIC) ใน Nginx still experimental ดังนั้น ModSecurity ยังไม่ support อย่างเต็มที่เพราะ HTTP/3 ใช้ QUIC protocol ไม่ใช่ TCP ซึ่งต่างจากที่ ModSecurity ออกแบบ ถ้าต้อง WAF สำหรับ HTTP/3 ให้ลอง Cloudflare WAF หรือ AWS WAF

ลบ OWASP CRS rules ไหนบ้างที่ strict มากไป?

บ่างองค์กร infotech ควร disable rules เช่น id:942251 (PHP code ใน parameters) ถ้า app legitimate ส่ง PHP code เช่น template engine แต่ suggestion ให้ลง detection mode ทดลองกับ CRS ที่ default ก่อน แล้วค่อยสร้าง whitelist สำหรับ false positive ที่แท้จริง อย่า disable rules โดยไม่ test เพราะการปิด rule มากไป = WAF กำหนิด protection จริง