ModSecurity พร้อมชุดกฎ OWASP CRS เปิดใช้ได้ในสิบนาทีและถูกปิดในสามวันต่อมา — หลังจากบทความในพื้นที่ผู้ดูแลบันทึกไม่ได้ การอัปโหลดไฟล์พัง และลูกค้าสั่งซื้อไม่ได้เพราะที่อยู่ของเขามีเครื่องหมายอะพอสทรอฟี ข้อสรุปว่า «WAF ขวางการทำงาน» ผุดขึ้นมาเอง และมันผิด: การบล็อกเหล่านั้นเกือบทั้งหมดแก้ได้ด้วยข้อยกเว้นที่แม่นยำสามถึงสี่ข้อ และเคล็ดลับทั้งหมดคือการหามันให้เจอถูกต้อง
อย่าเพิ่งเปิดโหมดบล็อกทันที
สัปดาห์แรกเป็นเพียงการสังเกตการณ์ ใน /etc/modsecurity/modsecurity.conf:
SecRuleEngine DetectionOnly
ในโหมดนี้ WAF บันทึกทุกอย่างที่มันจะบล็อกและไม่บล็อกอะไรเลย ทราฟฟิกจริงหนึ่งสัปดาห์ — รวมถึงงานของคุณเองในพื้นที่ผู้ดูแล การอัปโหลดรูปภาพ และการสั่งซื้อ — จะให้รายการผลบวกลวงที่เกิดขึ้นจริงแทนที่จะเป็นสมมติฐาน การเปลี่ยนไปเป็น On จึงสมเหตุสมผลเมื่อจัดการรายการนั้นเสร็จแล้วเท่านั้น
CRS ทำงานอย่างไร: ไม่ใช่กฎเดียวแต่เป็นผลรวม
นี่คือกุญแจสู่ทุกอย่างที่ตามมา CRS แทบไม่เคยบล็อกคำขอด้วยกฎเพียงข้อเดียว กฎทุกข้อที่ทำงานจะเพิ่มคะแนนความผิดปกติให้คำขอ และการบล็อกเกิดขึ้นเมื่อผลรวมข้ามเกณฑ์ นั่นคือเหตุผลที่ล็อกแสดงไม่ใช่หนึ่งบรรทัดแต่หลายบรรทัด และบรรทัดสุดท้ายคือกฎที่มีตัวระบุ 949110 — ตัวที่รวมคะแนน
ผลในทางปฏิบัติ: ต้องสร้างข้อยกเว้นให้กฎที่ให้คะแนน ไม่ใช่ให้ 949110 ถ้าปิดกฎที่รวมคะแนน ชุดกฎทั้งชุดก็ถูกปิด และ WAF ก็เหลือเป็นเพียงบรรทัดหนึ่งในไฟล์ตั้งค่า
ผลที่สองคือระดับ paranoia ค่าเริ่มต้นคือหนึ่ง และนั่นคือตัวเลือกที่ถูกต้อง ระดับ 2 และ 3 เพิ่มกฎที่ให้ผลบวกลวงบนเว็บไซต์ธรรมดาโดยการออกแบบ และควรเปิดใช้ก็ต่อเมื่อปรับระดับหนึ่งเสร็จสมบูรณ์แล้ว
หากฎที่เป็นต้นเหตุ
ทุกอย่างที่ต้องการอยู่ในล็อก audit (/var/log/modsec_audit.log) และในล็อกข้อผิดพลาดของเว็บเซิร์ฟเวอร์ ค้นตามเวลาที่ถูกบล็อก:
sudo grep -o 'id "[0-9]*"' /var/log/modsec_audit.log | sort | uniq -c | sort -rn | head
นั่นคือรายการความถี่ของกฎที่ทำงาน จากนั้นสำหรับตัวระบุที่เจาะจง ดูว่าอะไรกันแน่ที่ทำให้มันทำงาน:
sudo grep -A5 'id "942100"' /var/log/modsec_audit.log | head -40
ต้องการสามอย่าง: ตัวระบุกฎ ชื่อพารามิเตอร์ (ARGS:content, ARGS:comment) และเส้นทางของคำขอ ข้อยกเว้นสร้างขึ้นจากสิ่งเหล่านี้
ผู้ต้องสงสัยประจำ
รายการนี้ซ้ำกันจากเว็บไซต์หนึ่งไปอีกเว็บไซต์หนึ่ง:
- 942100 — SQL injection ทำงานกับฟิลด์ข้อความที่มีเนื้อหายาว: เนื้อบทความ คำอธิบายสินค้า ความคิดเห็น เครื่องหมายคำพูด วงเล็บ และคำอย่าง
selectในร้อยแก้วธรรมดาดูน่าสงสัยสำหรับตัวตรวจจับ; - 941100 และตระกูล 941xxx — XSS พวกมันมาพร้อมกับตัวแก้ไขแบบเห็นภาพ: การมีแท็ก HTML ในฟิลด์คือความหมายทั้งหมดของการทำงานของมัน;
- 920420 — Content-Type ที่ไม่ได้รับอนุญาต ทำให้ API และการอัปโหลดไฟล์พัง: ชุดประเภทที่อนุญาตโดยค่าเริ่มต้นนั้นแคบ และในเวอร์ชันเก่า
application/jsonไม่ได้อยู่ในนั้นเลย; - 913100 — ตัวสแกนตาม User-Agent จับเครื่องมือที่ชอบธรรมไปพร้อมกับตัวสแกน: การเฝ้าดูความพร้อมใช้งาน curl ในสคริปต์ของคุณเอง;
- 200002, 200004 — ข้อผิดพลาดในการอ่านเนื้อคำขอ ปกติแล้วไม่ได้หมายถึงการโจมตีแต่หมายถึงการเกินขีดจำกัดขนาดเนื้อคำขอ นั่นคือการอัปโหลดไฟล์ขนาดใหญ่
สามวิธีสร้างข้อยกเว้น
เรียงตามความหยาบจากน้อยไปมาก ทั้งหมดนี้ไปอยู่ในไฟล์ของคุณเอง (เช่น /etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES.conf) ไม่ใช่ในไฟล์ของ CRS เอง: ชุดกฎมีการอัปเดตและการแก้ไขของคุณจะหายไปพร้อมกับมัน
นำพารามิเตอร์หนึ่งตัวออกจากใต้กฎหนึ่งข้อ ตัวเลือกที่แม่นยำที่สุด และเป็นสิ่งที่ควรมุ่งไป:
SecRuleUpdateTargetById 942100 "!ARGS:content"
ปิดกฎเฉพาะบนเส้นทางเดียว เหมาะพอดีเมื่อหน้าใดหน้าหนึ่งส่งเสียงดัง — ตัวแก้ไข การนำเข้า ฟอร์มรีวิว:
SecRule REQUEST_URI "@beginsWith /admin/post" \
"id:1001,phase:1,pass,nolog,ctl:ruleRemoveById=942100"
ปิดกฎทั้งข้อ ทางเลือกสุดท้ายและเกือบทุกครั้งเป็นสัญญาณว่ายังหาสาเหตุไม่พบ:
SecRuleRemoveById 942100
ความต่างระหว่างแบบแรกกับแบบที่สามนั้นมาก ในกรณีแรก ฟิลด์เดียว — เนื้อบทความ — หยุดถูกตรวจ SQL injection ด้วยกฎข้อเดียว ในกรณีที่สองและสาม ทั้งเว็บไซต์หยุดถูกตรวจ ความต่างของความพยายามอยู่ที่ราวห้านาที
หลังแก้ไข ให้ตรวจไฟล์ตั้งค่าและโหลดใหม่อย่างนุ่มนวล:
sudo apachectl configtest && sudo systemctl reload apache2
sudo nginx -t && sudo systemctl reload nginx
ลำดับที่ช่วยประหยัดเวลาหนึ่งสัปดาห์
- หนึ่งสัปดาห์ใน
DetectionOnlyพร้อมการทำงานตามปกติ รวมถึงเว็บไซต์ พื้นที่ผู้ดูแล และการอัปโหลด - รายการความถี่ของกฎจากล็อก audit ไล่จากบนลงล่าง — สามถึงสี่ข้อแรกคิดเป็นเก้าสิบเปอร์เซ็นต์ของเสียงรบกวน
- สำหรับแต่ละข้อ: หาให้ได้ว่าพารามิเตอร์ไหนและบนหน้าไหน สร้างข้อยกเว้นตามพารามิเตอร์ ไม่ใช่ตามกฎ
- และเมื่อถึงตอนนี้จึงค่อย
SecRuleEngine On - เดือนละครั้ง ให้แวะดูการบล็อก: เว็บไซต์เปลี่ยนไป จึงมีผลบวกลวงใหม่เกิดขึ้น
ข้อสุดท้ายนี่แหละที่มักพังลง: ล็อก audit คือข้อความหลายกิกะไบต์และไม่มีใครจะอ่านมันด้วยมือ ความหมายของแผงที่รวบรวมไว้ก็คือให้รายการกฎที่ทำงาน คำขอที่ถูกบล็อก และชุดกฎที่ใช้งานอยู่ปรากฏต่อหน้าคุณ ไม่ใช่ต้องดึงออกมาด้วย grep ภาพนั้นเป็นอย่างไรดูได้ที่หน้าเดโมด้านล่าง