Antipattern: ใช้ตัวระบุความโลภในนโยบาย Regular ExpressionProtection

คุณกำลังดูเอกสารประกอบของ Apigee Edge
ไปที่ เอกสารประกอบของ Apigee X
info

นโยบาย RegularExpressionProtection กำหนดนิพจน์ทั่วไปที่จะได้รับการประเมินที่ รันไทม์ในพารามิเตอร์อินพิวต์หรือตัวแปรโฟลว์ โดยปกติแล้วคุณจะใช้นโยบายนี้เพื่อป้องกันภัยคุกคามด้านเนื้อหา เช่น การแทรก SQL หรือ JavaScript หรือเพื่อตรวจสอบพารามิเตอร์คำขอที่มีรูปแบบไม่ถูกต้อง เช่น อีเมลหรือ URL

คุณสามารถกำหนดนิพจน์ทั่วไปสำหรับเส้นทางคำขอ พารามิเตอร์การค้นหา พารามิเตอร์แบบฟอร์ม ส่วนหัว องค์ประกอบ XML (ในเพย์โหลด XML ที่กำหนดโดยใช้ XPath) แอตทริบิวต์ออบเจ็กต์ JSON (ในเพย์โหลด JSON ที่กำหนดโดยใช้ JSONPath)

ตัวอย่างนโยบาย RegularExpressionProtection ต่อไปนี้จะปกป้องแบ็กเอนด์จากการโจมตีด้วยการแทรก SQL

<!-- /antipatterns/examples/greedy-1.xml -->
<RegularExpressionProtection async="false" continueOnError="false" enabled="true"
  name="RegexProtection">
    <DisplayName>RegexProtection</DisplayName>
    <Properties/>
    <Source>request</Source>
    <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    <QueryParam name="query">
      <Pattern>[\s]*(?i)((delete)|(exec)|(drop\s*table)|
        (insert)|(shutdown)|(update)|(\bor\b))</Pattern>
    </QueryParam>
</RegularExpressionProtection>

รูปแบบที่ไม่แนะนำ

ตัวระบุปริมาณเริ่มต้น (*, + และ ?) มีลักษณะเป็นแบบ Greedy ซึ่งจะเริ่มจับคู่กับลำดับที่ยาวที่สุดเท่าที่จะเป็นไปได้ เมื่อไม่พบรายการที่ตรงกัน ตัวระบุปริมาณจะย้อนกลับทีละน้อยเพื่อพยายามจับคู่รูปแบบ หากสตริงผลลัพธ์ที่ตรงกับรูปแบบสั้นมาก การใช้ตัวระบุปริมาณแบบ Greedy อาจใช้เวลานานกว่าที่จำเป็น โดยเฉพาะอย่างยิ่งหากเพย์โหลดมีขนาดใหญ่ (หลายสิบหรือหลายร้อย KB)

นิพจน์ตัวอย่างต่อไปนี้ใช้ .* หลายอินสแตนซ์ ซึ่งเป็นโอเปอเรเตอร์แบบ Greedy

<Pattern>.*Exception in thread.*</Pattern>

ในตัวอย่างนี้ นโยบาย RegularExpressionProtection จะพยายามจับคู่ลำดับที่ยาวที่สุดเท่าที่จะเป็นไปได้ก่อน ซึ่งก็คือสตริงทั้งหมด หากไม่พบรายการที่ตรงกัน นโยบายจะย้อนกลับทีละน้อย หากสตริงที่ตรงกันอยู่ใกล้กับจุดเริ่มต้นหรือตรงกลางของเพย์โหลด การใช้ตัวระบุปริมาณแบบ Greedy เช่น .*อาจใช้เวลาและกำลังประมวลผลมากกว่าตัวระบุปริมาณแบบ Reluctant เช่น .*?หรือ (ไม่ค่อยพบ) ตัวระบุปริมาณแบบ Possessive เช่น .*+มาก

ตัวระบุปริมาณแบบ Reluctant (เช่น X*?, X+?, X??) จะเริ่มต้นด้วยการพยายามจับคู่อักขระเดียวจากจุดเริ่มต้นของเพย์โหลดและเพิ่มอักขระทีละน้อย ตัวระบุปริมาณแบบ Possessive (เช่น X?+, X*+, X++) จะพยายามจับคู่เพย์โหลดทั้งหมดเพียงครั้งเดียว

ข้อความตัวอย่างต่อไปนี้สำหรับรูปแบบด้านบน

Hello this is a sample text with Exception in thread
with lot of text after the Exception text.

การใช้ .* แบบ Greedy ไม่ได้ประสิทธิภาพในกรณีนี้ รูปแบบ .*Exception in thread.* ใช้ 141 ขั้นตอนในการจับคู่ หากคุณใช้รูปแบบ .*?Exception in thread.* (ซึ่งใช้ตัวระบุปริมาณแบบ Reluctant) แทน ผลลัพธ์จะเป็นเพียง 55 ขั้นตอน

ผลกระทบ

การใช้ตัวระบุปริมาณแบบ Greedy เช่น ไวลด์การ์ด (*) กับ นโยบาย RegularExpressionProtection อาจทำให้เกิดสิ่งต่อไปนี้

  • เวลาในการตอบสนองโดยรวมของคำขอ API เพิ่มขึ้นสำหรับเพย์โหลดขนาดปานกลาง (สูงสุด 1MB)
  • ใช้เวลานานขึ้นในการดำเนินการนโยบาย RegularExpressionProtection ให้เสร็จสมบูรณ์
  • คำขอ API ที่มีเพย์โหลดขนาดใหญ่ (>1MB) ล้มเหลวโดยมีข้อผิดพลาด 504 Gateway Timeout หากระยะหมดเวลาที่กำหนดไว้ล่วงหน้าหมดลงใน Edge Router
  • การใช้ CPU สูงใน Message Processor เนื่องจากมีการประมวลผลจำนวนมาก ซึ่งอาจส่งผลกระทบต่อคำขอ API อื่นๆ เพิ่มเติม

แนวทางปฏิบัติแนะนำ

  • หลีกเลี่ยงการใช้ตัวระบุปริมาณแบบ Greedy เช่น .* ในนิพจน์ทั่วไปกับนโยบาย RegularExpressionProtection แต่ให้ใช้ตัวระบุปริมาณแบบ Reluctant เช่น .*? หรือตัวระบุปริมาณแบบ Possessive เช่น .*+ (ไม่ค่อยพบ) ทุกครั้งที่เป็นไปได้

อ่านเพิ่มเติม