Antipattern: שימוש בכמים חמדן במדיניות regularExpressionProtection

מוצג המסמך של Apigee Edge.
עוברים אל מסמכי תיעוד של Apigee X.
מידע

במדיניות regularExpressionProtection מוגדרים ביטויים רגולריים שנבדקים זמן ריצה בפרמטרים של קלט או במשתני זרימה. בדרך כלל אתה משתמש במדיניות הזו כדי להגן מפני איומי תוכן, כמו SQL או החדרת JavaScript, או כדי לבדוק פרמטרים לא תקינים של בקשות. כמו כתובות אימייל או כתובות URL.

אפשר להגדיר את הביטויים הרגולריים עבור נתיבי בקשות, פרמטרים של שאילתה, פרמטרים של טפסים כותרות, רכיבי XML (במטען ייעודי (payload) של XML שמוגדר באמצעות XPath), מאפייני אובייקט JSON (ב-JSON מטען ייעודי (payload) שהוגדר באמצעות 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>

נגד דוגמת עיצוב

מכימות ברירת המחדל (*, + ו-?) הם חמדן ב- טבע: מתחילים להתאים לרצף הארוך ביותר שאפשר. אם לא נמצאה התאמה, לחזור לאחור בהדרגה כדי לנסות להתאים את הדפוס. אם המחרוזת שמתקבלת שתואמת לדפוס היא קצר מאוד, ולכן השימוש במכימות באמצעות אלגוריתם חמדן עשוי להימשך זמן רב יותר מהנדרש. במיוחד true אם המטען הייעודי (Payload) גדול (בעשרות או מאות KB).

הביטוי לדוגמה הבא משתמש במספר מופעים של .*, שהם חמדנים אופרטורים:

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

בדוגמה הזו, המדיניותregularExpressionProtection מנסה קודם כל להתאים למשך זמן ארוך ככל האפשר ברצף – כל המחרוזת. אם לא נמצאה התאמה, המדיניות תחזור אחורה בהדרגה. אם המחרוזת התואמת קרובה להתחלה או לאמצע של המטען הייעודי (Payload), משתמשים ברכיב לכימות חמדן כמו .* יכול להימשך הרבה יותר זמן וכוח עיבוד בהשוואה לחוסר רצון מגדירים כמו .*? או (פחות לעיתים קרובות) מכמים קנייניים כמו .*+.

מכמים לא פעילים (כמו X*?, X+?, X??) מתחילים בניסיון כך שיתאים לתו יחיד מתחילת המטען הייעודי (payload) ולהוסיף תווים בהדרגה. מכמים חזקים (כמו X?+, X*+, X++) מנסים להתאים את המטען הייעודי (payload) כולו פעם אחת בלבד.

בהינתן הטקסט לדוגמה הבא עבור התבנית שלמעלה:

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

השימוש באלגוריתם החמדן .* לא יניב ביצועים במקרה הזה. הדפוס כדי להתאים .*Exception in thread.*, צריך לבצע 141 שלבים. אם השתמשתם בקו ביטול הנעילה .*?Exception in thread.* (משתמשת בכמת נמנע) במקום זאת, התוצאה תהיה להיות רק 55 צעדים.

השפעה

שימוש במכימות באלגוריתם חמדן כמו תווים כלליים לחיפוש (*) עם הפרמטר המדיניות StandardExpressionProtection יכולה להוביל ל:

  • עלייה בזמן האחזור הכולל של בקשות API בגודל מטען ייעודי (payload) בינוני (עד 1MB)
  • זמן ארוך יותר להשלמת הביצוע של המדיניות regularExpressionProtection
  • בקשות API עם מטענים ייעודיים (payloads) גדולים (יותר מ-1MB) נכשלות עם 504 שגיאות זמן קצוב לתפוגה של שער, אם בנתב Edge עוברים תקופה מוגדרת מראש של זמן קצוב לתפוגה
  • ניצול גבוה של המעבד (CPU) במעבדי הודעות בגלל כמות גדולה של עיבודים שעלולה להמשיך השפעה על בקשות API אחרות

שיטה מומלצת

  • הימנעו משימוש במכימות חמדן כמו .* בביטויים רגולריים עם regularExpressionProtection. במקום זאת, השתמשו במכמתים חסרי רצון כמו .*? או מכימות קנייניים כמו .*+ (פחות נפוץ) בכל מקום ככל האפשר.

קריאה נוספת