ฉันควรจะหนีการเฉือน /
ใน เขียนซ้ำ
?
โดย "escape the slash" คุณหมายถึง "ฉันควรจับคู่ URL ที่เข้ารหัสเครื่องหมายทับหรือไม่" ขึ้นอยู่กับคำขอ HTTP ที่ส่งไปยังเซิร์ฟเวอร์ของคุณทั้งหมด
แต่ฉันตรวจสอบ https://serverfault.com/a/968916/280923 และมันบอกว่า "เครื่องหมายทับ (/
) ไม่ต้องหนี" ผมก็เลยงง
คำถาม/คำตอบที่เชื่อมโยงไม่เกี่ยวข้องกับปัญหาปัจจุบัน คำถามนั้นเกี่ยวข้องกับการหลีกเครื่องหมายแบ็กสแลชในคำสั่ง Apache/regex ไม่ใช่ URL ที่เข้ารหัส URL (หรือเข้ารหัส %) ที่คุณกำลังจัดการที่นี่ นี่เป็นวิธีการ "หลบหนี" สองประเภทที่แตกต่างกันมากสำหรับวัตถุประสงค์ที่แตกต่างกัน
สิ่งที่คุณกำลังจัดการคือ %-encoded URL URL ปรากฏในคำขอ HTTP อย่างไร ส่วนต่างๆ ของ URL (โดยเฉพาะอย่างยิ่ง "เส้นทาง" และ "สตริงข้อความค้นหา") มีข้อกำหนดในการเข้ารหัสที่แตกต่างกัน ไม่ว่าจะเป็นตัวละครเฉพาะ ความต้องการ การจะเข้ารหัส % ขึ้นอยู่กับว่าจะมีความหมายพิเศษในบริบทนั้นหรือไม่
ตามที่กำหนดไว้ใน RFC3986, เครื่องหมายทับ (/
) ไม่จำเป็นต้องเข้ารหัส % อย่างเคร่งครัดในส่วนสตริงข้อความค้นหาของ URL อย่างไรก็ตาม ฟังก์ชันการเข้ารหัส URL (เช่น ใน PHP และ JavaScript) มักจะ %-เข้ารหัสอักขระนี้ (ฉันคิดว่านี่เป็นเรื่องในอดีตเป็นส่วนใหญ่เนื่องจากการใช้งานแบบเก่าบางรายการไม่ได้จัดการเครื่องหมายทับที่ไม่ได้เข้ารหัสอย่างถูกต้อง - อ้างอิง RFC3986.)
อย่างไรก็ตามไม่ว่าจะเป็นตัวละคร ความต้องการ ในการเข้ารหัส URL (เพื่อลบล้างความหมายพิเศษ) อักขระใดๆ สามารถเข้ารหัส % ได้ และควรได้รับการปฏิบัติเช่นเดียวกับอักขระที่เป็นตัวอักษร (ไม่ได้เข้ารหัส)
ไม่ว่าคุณจะต้องการจับคู่หรือไม่ /
(ถอดรหัส) หรือ %2F
(เข้ารหัส) ขึ้นอยู่กับว่าอักขระนั้นถูกเข้ารหัส % ในคำขอหรือไม่
ปัญหาของคุณก็คือว่า QUERY_STRING
ตัวแปรเซิร์ฟเวอร์ไม่ได้ถอดรหัส % ซึ่งแตกต่างจากเส้นทาง URL ที่จับคู่โดย เขียนกฎใหม่
ลวดลาย.
แต่... คุณต้องตรวจสอบทั้ง %-decoded หรือไม่ /
และ %-เข้ารหัส %2F
? สันนิษฐานว่าคุณกำลังลิงก์ไปยัง URL (ตามรูปแบบบัญญัติ) เพียงรายการเดียวหรือ URL อื่นอย่างสม่ำเสมอ ดังนั้น คำขอใดๆ ที่ส่งไปยัง URL ที่ไม่ใช่ตามรูปแบบบัญญัติจะต้องพิมพ์ด้วยตนเองหรือเชื่อมโยงไปยังบุคคลที่สามอย่างไม่ถูกต้อง คุณได้รับคำขอทั้งสองหรือไม่ อะไรคือผลของการไม่เปลี่ยนเส้นทาง URL ที่ไม่ใช่ตามรูปแบบบัญญัติ
มิฉะนั้น ใช่ คุณจะต้องตรวจสอบทั้งสองอย่าง (และอาจเป็นรูปแบบ/กรณีทั้งหมด) แม้ว่านี่จะเป็นเพียงแค่ /ฐานความรู้/
หรือ %2Fฐานความรู้%2F
. แต่โปรดทราบว่าอาจเป็นได้ %2F
(ตัวพิมพ์ใหญ่) หรือ %2ฉ
(ตัวพิมพ์เล็ก). ตัวพิมพ์ใหญ่เป็นเพียงแบบแผน ต้องตรวจสอบการเข้ารหัสแบบผสม เช่น %2Fฐานความรู้/
น่าจะหายากมาก แต่นำไปมากนี้ก็เช่นเดียวกับ %2f%6b%6e%6f%77%6c%65%64%67%65%62%61%73%65%2f
. คุณจะต้องจัดการกับรูปแบบเหล่านี้ทั้งหมดหรือไม่นั้นขึ้นอยู่กับความเป็นไปได้ที่จะได้รับคำขอดังกล่าวและความรุนแรงของกฎที่ไม่ตรงกัน
ดังนั้นเพื่อให้ตรงกับทั้งสอง /ฐานความรู้/
และ %2Fฐานความรู้%2F
(ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่) คุณสามารถใช้สิ่งต่อไปนี้:
RewriteCond %{QUERY_STRING} ^rp=(/|%2[Ff])ฐานความรู้(/|%2[Ff])
คุณสามารถหลีกเลี่ยงคลาสตัวละครได้ [เอฟ]
และใช้ เอ็น.ซี
ตั้งค่าสถานะแทนเพื่อให้การเปรียบเทียบทั้งหมดไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่ ตัวอย่างเช่น:
RewriteCond %{QUERY_STRING} ^rp=(/|%2F)ฐานความรู้(/|%2F) [NC]
บน Apache 2.4 คุณสามารถใช้ไฟล์ ยูสเคป()
ทำงานในนิพจน์ Apache ด้วย เขียนซ้ำ
คำสั่งไปยัง URL ถอดรหัส QUERY_STRING
ก่อนทำการเปรียบเทียบ อย่างไรก็ตาม สิ่งนี้ไม่ได้ช่วยคุณได้จริงๆ เนื่องจากมันไม่ได้ %-decode ทับ เช่น %2F
หรือ %2ฉ
ยังคงอยู่ตามคำขอ (แต่อักขระอื่น ๆ จะถูก % -decoded) ตัวอย่างเช่น:
RewriteCond expr "unescape(%{QUERY_STRING}) =~ m#^rp=(/|%2[Ff])ฐานความรู้(/|%2[Ff])#"
สิ่งนี้จะช่วยให้คุณจับคู่ได้ rp=%2f%6b%6e%6f%77%6c%65%64%67%65%62%61%73%65%2f
.
หรือหากคุณไม่ต้องการให้มีอักขระเข้ารหัส URL ในสตริงข้อความค้นหา คุณก็สามารถบล็อกคำขอใดๆ ที่ส่งใดๆ ก็ได้! ตัวอย่างเช่น สิ่งต่อไปนี้จะต้องอยู่ที่ด้านบนสุดของการกำหนดค่าของคุณ:
# บล็อกคำขอใดๆ ที่มีอักขระ %-encoded ในสตริงข้อความค้นหา
RewriteCond %{QUERY_STRING} %[\da-f]{2} [NC]
RewriteRule ^ - [R=400]