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

ลำดับที่ช่วยประหยัดเวลาหนึ่งสัปดาห์

  1. หนึ่งสัปดาห์ใน DetectionOnly พร้อมการทำงานตามปกติ รวมถึงเว็บไซต์ พื้นที่ผู้ดูแล และการอัปโหลด
  2. รายการความถี่ของกฎจากล็อก audit ไล่จากบนลงล่าง — สามถึงสี่ข้อแรกคิดเป็นเก้าสิบเปอร์เซ็นต์ของเสียงรบกวน
  3. สำหรับแต่ละข้อ: หาให้ได้ว่าพารามิเตอร์ไหนและบนหน้าไหน สร้างข้อยกเว้นตามพารามิเตอร์ ไม่ใช่ตามกฎ
  4. และเมื่อถึงตอนนี้จึงค่อย SecRuleEngine On
  5. เดือนละครั้ง ให้แวะดูการบล็อก: เว็บไซต์เปลี่ยนไป จึงมีผลบวกลวงใหม่เกิดขึ้น

ข้อสุดท้ายนี่แหละที่มักพังลง: ล็อก audit คือข้อความหลายกิกะไบต์และไม่มีใครจะอ่านมันด้วยมือ ความหมายของแผงที่รวบรวมไว้ก็คือให้รายการกฎที่ทำงาน คำขอที่ถูกบล็อก และชุดกฎที่ใช้งานอยู่ปรากฏต่อหน้าคุณ ไม่ใช่ต้องดึงออกมาด้วย grep ภาพนั้นเป็นอย่างไรดูได้ที่หน้าเดโมด้านล่าง