הגדרת מגבלות הזמנות לפי IP ב-1С-ביטריקס
תת-רשת IP אחת מייצרת 50 הזמנות תוך 10 דקות. הסיבה — הזרקת הונאה המונית או באג בחזית עם שליחת טופס חוזרת. הגבלת קצב הזמנות לפי IP מגנה על מסד הנתונים מזבל ומונעת הפסדים כספיים. הזמנות הונאה עולות לחנות סכומים רציניים: אריזה, משלוח, החזרות. יישום מגבלות קצב מפחית הזמנות הונאה ב-80% ומקטין תוצאות חיוביות שגויות ב-90% לפי נתוני המקרים שלנו. במשך שנים של עבודה עם ביטריקס, פיתחנו פתרון מוכן שנפרס במלואו תוך 2-3 ימים. צוות שלנו של 10 מפתחי ביטריקס השלים מעל 150 פרויקטים של מסחר אלקטרוני, כולל יותר מ-100 יישומי הגנה על הזמנות.
למה מגבלות IP חשובות לחנות מקוונת?
רמאים משתמשים בסקריפטים אוטומטיים כדי לבצע הזמנות עם נתונים מזויפים. IP אחד יכול ליצור עשרות הזמנות בדקה, לסתום את המערכת ולגרום לניכוי מלאי שגוי. הגבלות הזמנות ברמת IP הן קו ההגנה הראשון, המנתקות התקפות כאלה לפני שהן משפיעות על יתרות המלאי ופעולות פיננסיות.
איך פועלות הגבלות הזמנות לפי IP?
המנגנון פשוט: לפני שמירת הזמנה, אנו בודקים את מספר ההזמנות מאותו IP ב-N הדקות האחרונות. אם חריגה מהסף, ההזמנה נדחית עם הודעה ברורה. אנו משתמשים בשתי רמות הגנה: מהירה ב-nginx ומפורטת ב-PHP.
מגבלות ברמת PHP
בדיקה במטפל האירועים לפני שמירת הזמנה:
namespace Local\Fraud; class IpOrderLimiter { // Лимиты: [интервал в минутах => максимум заказов] private const LIMITS = [ 15 => 3, // не более 3 заказов за 15 минут 60 => 5, // не более 5 заказов за 1 час 1440 => 15, // не более 15 заказов за сутки ]; public static function check(string $ip): ?string { $conn = \Bitrix\Main\Application::getConnection(); $ipSafe = $conn->getSqlHelper()->forSql($ip); foreach (self::LIMITS as $minutes => $maxOrders) { $from = date('Y-m-d H:i:s', time() - $minutes * 60); $count = (int)$conn->query( "SELECT COUNT(*) cnt FROM b_sale_order WHERE CREATED_BY_IP = '{$ipSafe}' AND DATE_INSERT >= '{$from}'" )->fetch()['cnt']; if ($count >= $maxOrders) { return "Превышен лимит заказов с вашего IP. Попробуйте через " . self::cooldownMinutes($minutes, $maxOrders, $ip) . " минут."; } } return null; } private static function cooldownMinutes(int $windowMinutes, int $max, string $ip): int { $conn = \Bitrix\Main\Application::getConnection(); $ipSafe = $conn->getSqlHelper()->forSql($ip); $from = date('Y-m-d H:i:s', time() - $windowMinutes * 60); // Находим самый ранний из последних $max заказов $oldest = $conn->query( "SELECT MIN(DATE_INSERT) dt FROM ( SELECT DATE_INSERT FROM b_sale_order WHERE CREATED_BY_IP = '{$ipSafe}' AND DATE_INSERT >= '{$from}' ORDER BY DATE_INSERT ASC LIMIT {$max} ) sub" )->fetch()['dt']; if (!$oldest) return $windowMinutes; $oldestTs = strtotime($oldest); return max(1, (int)ceil(($oldestTs + $windowMinutes * 60 - time()) / 60)); } } מטפל אירועים:
AddEventHandler('sale', 'OnBeforeOrderFinalAction', function(\Bitrix\Sale\Order $order) { if ($order->getId() > 0) return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS); $ip = $_SERVER['REMOTE_ADDR'] ?? ''; $error = \Local\Fraud\IpOrderLimiter::check($ip); if ($error) { return new \Bitrix\Main\EventResult( \Bitrix\Main\EventResult::ERROR, new \Bitrix\Main\Error($error) ); } return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS); }); לפי תיעוד ביטריקס על OnBeforeOrderFinalAction, האירוע נקרא לפני הפעולה הסופית עם ההזמנה — מקום אידיאלי לבדיקות מונעות.
מגבלות ברמת nginx
מגבלות nginx יעילות יותר כי הן פועלות לפני PHP, ולא מבזבזות משאבי שרת על ביצוע סקריפט. עבור חנות עם תעבורת הזמנות גבוהה, זה מפחית את עומס ה-PHP ב-70% בהשוואה לבדיקות PHP בלבד. בנוסף, nginx לא מחכה לתגובת האפליקציה — החסימה מתרחשת ברמת ליבת שרת האינטרנט. הגבלת קצב ב-nginx מהירה פי 2 מבדיקות מבוססות PHP, מה שהופך אותה לקו ראשון אופטימלי.
# /etc/nginx/conf.d/order-limit.conf # Зона для страницы оформления заказа limit_req_zone $binary_remote_addr zone=checkout:10m rate=2r/m; # Зона для AJAX-запросов создания заказа limit_req_zone $binary_remote_addr zone=order_ajax:10m rate=5r/m; server { # ... location = /order/ { limit_req zone=checkout burst=3 nodelay; limit_req_status 429; # ... } location ~ ^/local/ajax/(order|checkout) { limit_req zone=order_ajax burst=5 nodelay; limit_req_status 429; add_header Retry-After 60; # ... } } רשימת IP לבנה ורישום
שותפים לגיטימיים או IP פנימיים לא צריכים להיות כפופים למגבלות:
private static function isWhitelisted(string $ip): bool { $whitelist = [ '127.0.0.1', '::1', '10.0.0.0/8', // внутренняя сеть '192.168.0.0/16', ]; foreach ($whitelist as $cidr) { if (str_contains($cidr, '/')) { if (self::ipInCidr($ip, $cidr)) return true; } elseif ($ip === $cidr) { return true; } } return false; } private static function ipInCidr(string $ip, string $cidr): bool { [$subnet, $mask] = explode('/', $cidr); return (ip2long($ip) & ~((1 << (32 - (int)$mask)) - 1)) === ip2long($subnet); } כל הפעלת מגבלה מתועדת:
\Bitrix\Main\Diag\Debug::writeToFile( [ 'ip' => $ip, 'limit' => "{$count}/{$maxOrders} за {$minutes} мин", 'ua' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'referer' => $_SERVER['HTTP_REFERER'] ?? '', ], 'IP limit triggered', '/local/logs/ip-limits.log' ); סוכן יומי מנתח את היומן ושולח דוח: 10 ה-IP המובילים לפי חסימות, דינמיקה שבועית.
טיפול בתוצאות חיוביות שגויות
תוצאות חיוביות שגויות מתרחשות כאשר משתמשים לגיטימיים (למשל, מרשת משרדית אחת) חורגים מהמגבלות. הפתרון הוא הגדרת רשימה לבנה עבור תת-רשתות ארגוניות או הגדלת מגבלות עבור תרחישי B2B. בניסיון שלנו, התאמת ספים פותרת 80% מהמקרים ללא שינויי קוד.
השוואת גישות: PHP לעומת nginx
| קריטריון | מגבלות PHP | מגבלות nginx |
|---|---|---|
| עומס שרת | בינוני (ביצוע PHP, שאילתות DB) | מינימלי (ליבת nginx) |
| גמישות לוגית | גבוהה (רשימה לבנה, מרווחים מותאמים) | נמוכה (רק קצב בקשות) |
| מהירות חסימה | לאחר התחלת PHP | לפני עיבוד PHP |
| המלצה | ללוגיקה מפורטת | קו ראשון, הפחתת עומס |
איך ליישם הגבלת קצב IP: מדריך שלב אחר שלב
- בדיקת הארכיטקטורה הנוכחית: זיהוי נקודות עיבוד הזמנות, קביעת כתובות IP בשימוש.
- הגדרת מגבלות nginx: הוספת
namespace Local\Fraud; class IpOrderLimiter { // Лимиты: [интервал в минутах => максимум заказов] private const LIMITS = [ 15 => 3, // не более 3 заказов за 15 минут 60 => 5, // не более 5 заказов за 1 час 1440 => 15, // не более 15 заказов за сутки ]; public static function check(string $ip): ?string { $conn = \Bitrix\Main\Application::getConnection(); $ipSafe = $conn->getSqlHelper()->forSql($ip); foreach (self::LIMITS as $minutes => $maxOrders) { $from = date('Y-m-d H:i:s', time() - $minutes * 60); $count = (int)$conn->query( "SELECT COUNT(*) cnt FROM b_sale_order WHERE CREATED_BY_IP = '{$ipSafe}' AND DATE_INSERT >= '{$from}'" )->fetch()['cnt']; if ($count >= $maxOrders) { return "Превышен лимит заказов с вашего IP. Попробуйте через " . self::cooldownMinutes($minutes, $maxOrders, $ip) . " минут."; } } return null; } private static function cooldownMinutes(int $windowMinutes, int $max, string $ip): int { $conn = \Bitrix\Main\Application::getConnection(); $ipSafe = $conn->getSqlHelper()->forSql($ip); $from = date('Y-m-d H:i:s', time() - $windowMinutes * 60); // Находим самый ранний из последних $max заказов $oldest = $conn->query( "SELECT MIN(DATE_INSERT) dt FROM ( SELECT DATE_INSERT FROM b_sale_order WHERE CREATED_BY_IP = '{$ipSafe}' AND DATE_INSERT >= '{$from}' ORDER BY DATE_INSERT ASC LIMIT {$max} ) sub" )->fetch()['dt']; if (!$oldest) return $windowMinutes; $oldestTs = strtotime($oldest); return max(1, (int)ceil(($oldestTs + $windowMinutes * 60 - time()) / 60)); } }לדפי תשלום ובקשות AJAX, קביעת ספים בסיסיים. - פיתוח מחלקת PHP
AddEventHandler('sale', 'OnBeforeOrderFinalAction', function(\Bitrix\Sale\Order $order) { if ($order->getId() > 0) return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS); $ip = $_SERVER['REMOTE_ADDR'] ?? ''; $error = \Local\Fraud\IpOrderLimiter::check($ip); if ($error) { return new \Bitrix\Main\EventResult( \Bitrix\Main\EventResult::ERROR, new \Bitrix\Main\Error($error) ); } return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS); });: יישום בדיקות עם חלונות זמן גמישים ורשימה לבנה. שימוש בבלוק Highload לאחסון הגדרות מגבלה — זה מאפשר שינוי ספים ללא פריסה. - אינטגרציה עם אירוע
OnBeforeOrderFinalAction: חיבור מטפל ב-# /etc/nginx/conf.d/order-limit.conf # Зона для страницы оформления заказа limit_req_zone $binary_remote_addr zone=checkout:10m rate=2r/m; # Зона для AJAX-запросов создания заказа limit_req_zone $binary_remote_addr zone=order_ajax:10m rate=5r/m; server { # ... location = /order/ { limit_req zone=checkout burst=3 nodelay; limit_req_status 429; # ... } location ~ ^/local/ajax/(order|checkout) { limit_req zone=order_ajax burst=5 nodelay; limit_req_status 429; add_header Retry-After 60; # ... } }או מודול מותאם. - רישום וניטור: הגדרת תיעוד הפעלות וסוכן יומי לדיווח.
- בדיקה: הדמיית חריגה ממגבלות מ-IP שונים, הבטחת חסימה נכונה.
- השקה והתאמה: ניטור יומנים בשבוע הראשון, התאמת ספים במידת הצורך.
הגדרת מגבלות לתרחישים שונים
| תרחיש חנות | מגבלות מומלצות |
|---|---|
| B2C סטנדרטי | 3/15 דקות, 5/שעה, 15/יום |
| B2B עם הזמנות גדולות | 5/15 דקות, 15/שעה, 50/יום |
| מבצע (זמני) | 10/15 דקות, 30/שעה |
המגבלות מאוחסנות בקונפיגורציה או באפשרויות מודול — ניתן לשנות דרך פאנל הניהול ללא פריסה.
מה כלול
- בדיקת ארכיטקטורה נוכחית וזיהוי נקודות תורפה.
- פיתוח מחלקת PHP IpOrderLimiter עם מגבלות גמישות ורשימה לבנה.
- הגדרת nginx להגנה בקו ראשון.
- אינטגרציה עם אירוע
private static function isWhitelisted(string $ip): bool { $whitelist = [ '127.0.0.1', '::1', '10.0.0.0/8', // внутренняя сеть '192.168.0.0/16', ]; foreach ($whitelist as $cidr) { if (str_contains($cidr, '/')) { if (self::ipInCidr($ip, $cidr)) return true; } elseif ($ip === $cidr) { return true; } } return false; } private static function ipInCidr(string $ip, string $cidr): bool { [$subnet, $mask] = explode('/', $cidr); return (ip2long($ip) & ~((1 << (32 - (int)$mask)) - 1)) === ip2long($subnet); }. - מערכת רישום וסוכן דיווח.
- תיעוד והדרכת מנהלים.
לתמחור ולוחות זמנים, צרו קשר — נספק הצעה מותאמת לפרויקט שלכם.
יש לנו מעל 5 שנות ניסיון בפיתוח ביטריקס ויותר מ-100 יישומים מוצלחים של הגנה על הזמנות. מומחים מוסמכים עם שנים של ניסיון. קבלו ייעוץ על הגדרת מגבלות לחנות שלכם — צרו קשר.







