כשהמשתמש מספק את ה-regex: שורה אחת שהפילה את ה-API

Read this article in English

מי חשב שביטוי רגולרי תמים יכול לגרום לקריסת המערכת?

במערכת שבה בדקתי לאחרונה נתקלתי בחולשה שנראית תמימה, אבל בפועל פתחה פתח להזרקת קוד. באפליקציה היה שדה חיפוש מתקדם שנועד לאפשר למשתמשים לסנן נתונים לפי ביטוי רגולרי. המשתמש היה שולח payload בסגנון:

POST /api/search
{
 "regex": "^[A-Z]{3}[0-9]{4}$"
}

הקוד בצד השרת השתמש ישירות ב-new Regex(userInput) כדי להריץ את הביטוי על מסד הנתונים. הבעיה היא שלא בוצעה שום ולידציה על הביטוי שנכנס.

מה שתוקף שולח במקום

regex זדוני שגורם ל-catastrophic backtracking:

^(a+)+$

ואז מחרוזת יחסית קצרה כמו aaaaaaaaaaaaaaaaaaaaaaaa! שגורמת ל-regex engine להיתקע ולצרוך CPU במשך שניות ארוכות. כשהתוקף שלח כמה בקשות כאלה במקביל, כל ה-worker threads ננעלו, וה-API כולו הפסיק להגיב. בפועל זה ReDoS קלאסי – denial of service דרך regular expressions.

כדי להבין את ההשלכות תדמיינו את זה בפרודקשן בשעת עומס: עשרות משתמשים מחוברים, שולחים בקשות קריטיות לעסק. תוקף אחד מפעיל regex תמים למראה, ושנייה לאחר מכן השרת מזנק ל-100% CPU. הקריאות הלגיטימיות נתקעות בתור, דוחות לא נשלחים, עסקאות לא מתבצעות. צוותי התמיכה מוצפים בתלונות, לוחות הבקרה נדלקים באדום והמערכת כולה קורסת. מה שנראה כבאג זניח בקוד הפך בן רגע להשבתה מוחלטת.

מה שמסוכן כאן זה שהכול נראה כ-feature לגיטימי

אנחנו כמפתחים אוהבים לעיתים לתת גמישות למשתמשים, במיוחד כשהם רוצים פיצ’ר של חיפוש דינמי. אבל בלי לחשוב על ההשלכות, המערכת קיבלה אפשרות להריץ ביטוי רגולרי שמגיע ישירות מהמשתמש על שרת פרודקשן.

איך פותרים

  • לא לאפשר למשתמש לספק ביטוי רגולרי גולמי. במקום זה לתת סט של פילטרים מוגדרים מראש או DSL בטוח.
  • אם חייבים לתמוך ב-regex חופשי, להריץ אותו בתוך sandbox מבודד עם timeout קשיח.
  • להשתמש באלגוריתמים non-backtracking כמו RE2 או ספריות דומות שלא מאפשרות catastrophic backtracking.
  • לנטר שימוש חריג ולזהות בקשות שחוזרות על עצמן עם regex חשודים.

זה מקרה שממחיש שוב איך שימוש לגיטימי בפיצ’רים של שפה או ספרייה הופך לכלי נשק בידי תוקף. לא צריך SQL injection כדי להפיל מערכת – מספיק שורת קוד שמקבלת regex מהמשתמש בלי לחשוב על מה קורה מתחת לפני השטח.


פוסט זה פורסם לראשונה בלינקדאין בתאריך 2025-09-22. — ארז מטולה