الگوی بد: استفاده از کمیت‌گرهای حریص در خط‌مشی «محافظت از عبارت باقاعده»

درحال مشاهده اسناد Apigee Edge هستید.
به اسناد Apigee X بروید.
اطلاعات

خط‌مشی RegularExpressionProtection عبارت‌های باقاعده‌ای را تعریف می‌کند که در زمان اجرا روی متغیرهای جریان یا پارامترهای ورودی ارزیابی می‌شوند. معمولاً از این خط‌مشی برای محافظت دربرابر تهدیدهای محتوا مثل تزریق SQL یا جاوا اسکریپت، یا برای بررسی پارامترهای درخواست بدشکل مثل نشانی‌های ایمیل یا نشانی‌های وب استفاده می‌کنید.

عبارت‌های باقاعده را می‌توان برای مسیرهای درخواست، پارامترهای پُرسمان، پارامترهای فرم، سرایندها، عناصر 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>

الگوی بد

کمیت‌گرهای پیش‌فرض (*،‏ +، و ?) در ماهیت خود حریص هستند: آن‌ها با طولانی‌ترین توالی ممکن شروع به مطابقت می‌کنند. وقتی تطابقی پیدا نمی‌شود، آن‌ها به‌تدریج به عقب برمی‌گردند تا الگو را مطابقت دهند. اگر رشته حاصل که با الگو مطابقت دارد بسیار کوتاه باشد، استفاده از کمیت‌گرهای حریص می‌تواند زمان بیشتری از حد لازم طول بکشد. این موضوع به‌ویژه اگر بار بزرگ باشد (در حد ده‌ها یا صدها کیلوبایت) صادق است.

عبارت نمونه زیر از چندین نمونه .* استفاده می‌کند که کاربران حریص هستند:

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

در این مثال، خط‌مشی RegularExpressionProtection ابتدا تلاش می‌کند طولانی‌ترین توالی ممکن—کل رشته—را مطابقت دهد. اگر هیچ تطابقی پیدا نشود، خط‌مشی به‌تدریج به عقب برمی‌گردد. اگر رشته منطبق نزدیک به شروع یا میانه محموله باشد، استفاده از کمیت‌گر حریص مثل .* می‌تواند زمان و توان پردازشی بسیار بیشتری نسبت‌به کمیت‌گرهای بی‌میل مثل .*? یا (کمتر رایج) کمیت‌گرهای تملکی مثل .*+ بگیرد.

کمیت‌گرهای بی‌میل (مثل X*?، X+?، X??) با تلاش برای مطابقت دادن یک نویسه از ابتدای داده‌بر شروع می‌کنند و به‌تدریج نویسه‌ها را اضافه می‌کنند. کمیت‌گرهای مالکانه (مثل X?+، X*+، X++) سعی می‌کنند کل بار را فقط یک‌بار مطابقت دهند.

با درنظر گرفتن نوشتار نمونه زیر برای الگوی بالا:

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

استفاده از .* حریص در این مورد عملکرد خوبی ندارد. الگوی .*Exception in thread.* برای مطابقت دادن ۱۴۱ مرحله نیاز دارد. اگر از الگوی .*?Exception in thread.* (که از کمیت‌گر بی‌میل استفاده می‌کند) استفاده می‌کردید، نتیجه فقط ۵۵ مرحله می‌شد.

تأثیر

استفاده از کمیت‌گرهای حریص مثل نویسه‌های عام (*) با خط‌مشی «محافظت از عبارت باقاعده» می‌تواند منجر به موارد زیر شود:

  • افزایش در تأخیر کلی برای درخواست‌های API برای اندازه بار متوسط (تا ۱ مگابایت)
  • زمان طولانی‌تر برای تکمیل اجرای خط‌مشی RegularExpressionProtection
  • درخواست‌های API با بار بزرگ (>1MB) درصورت سپری شدن دوره مهلت زمانی ازپیش تعریف‌شده در «مسیریاب لبه» با خطاهای «۵۰۴ پایان مهلت زمانی دروازه» ناموفق می‌شوند
  • استفاده زیاد از CPU در «پردازشگرهای پیام» به‌دلیل حجم زیاد پردازش که می‌تواند بر درخواست‌های دیگر «میانای برنامه‌سازی کاربردی» تأثیر بگذارد

روال مطلوب

  • از استفاده از کمیت‌گرهای حریص مثل .* در عبارت‌های باقاعده با خط‌مشی «محافظت از عبارت باقاعده» خودداری کنید. درعوض، از کمیت‌گرهای بی‌میل مانند .*? یا کمیت‌گرهای مالکانه مانند .*+ (کمتر رایج) در هرجا که امکان‌پذیر است استفاده کنید.

مطالعه بیشتر