Налаштування лімітів замовлень за IP-адресою 1С-Бітрікс
Одна IP-підмережа генерує 50 замовлень за 10 хвилин. Причина — масовий шахрайський вкид або баг на фронтенді з повторним відправленням форми. Ліміти за IP захищають базу даних від сміття та запобігають фінансовим втратам. Шахрайські замовлення обходяться магазину в серйозні суми: упаковка, доставка, повернення. Впровадження лімітів знижує повернення за шахрайськими замовленнями на 80% (за даними наших кейсів). За роки роботи з Бітрікс ми розробили готове рішення, яке ставиться під ключ за 2-3 дні.
Чому ліміти за 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 ефективніші? Nginx обробляє ліміти до PHP, не витрачаючи серверні ресурси на виконання скриптів. Для магазину з великим потоком замовлень це знижує навантаження на PHP на 70%. Крім того, nginx не чекає відповіді від додатку — блокування відбувається на рівні ядра веб-сервера.
# /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 vs nginx
| Критерій | Ліміти на PHP | Ліміти на nginx |
|---|---|---|
| Навантаження на сервер | Середнє (виконання PHP, запити до БД) | Мінімальне (ядро nginx) |
| Гнучкість логіки | Висока (білий список, кастомні інтервали) | Низька (тільки частота запитів) |
| Швидкість блокування | Після початку виконання PHP | До обробки PHP |
| Рекомендація | Для детальної логіки | Перший рубіж, зниження навантаження |
Як впровадити ліміти замовлень за IP: покрокове керівництво
- Аудит поточної архітектури: виявити точки обробки замовлень, визначити використовувані IP-адреси.
- Налаштування лімітів на nginx: додати
limit_req_zoneдля сторінок оформлення та AJAX-запитів, встановити базові пороги. - Розробка PHP-класу
IpOrderLimiter: реалізувати перевірку з гнучкими часовими вікнами та білим списком. Для зберігання конфігурації лімітів можна використовувати HL-блок — це дозволить змінювати пороги без деплою. - Інтеграція з подією
OnBeforeOrderFinalAction: підключити обробник уinit.phpабо кастомному модулі. - Логування та моніторинг: налаштувати запис спрацювань та агент для щоденного надсилання звіту.
- Тестування: симулювати перевищення ліміту з різних IP, переконатися в коректному блокуванні.
- Запуск та адаптація: спостерігати за логами перший тиждень, при необхідності коригувати пороги.
Налаштування лімітів для різних сценаріїв
| Сценарій магазину | Рекомендовані ліміти |
|---|---|
| Стандартний B2C | 3/15хв, 5/год, 15/добу |
| B2B з великими замовленнями | 5/15хв, 15/год, 50/добу |
| Розпродаж (тимчасово) | 10/15хв, 30/год |
Ліміти зберігаються в конфігу або опціях модуля — без деплою змінюються через адміністративну частину.
Що входить у роботу
- Аудит поточної архітектури та виявлення вразливих місць.
- Розробка PHP-класу IpOrderLimiter з гнучкими лімітами та білим списком.
- Налаштування nginx для першого рубежу захисту.
- Інтеграція з подією
OnBeforeOrderFinalAction. - Система логування та агент звітів.
- Документація та навчання адміністратора.
Для розрахунку вартості та термінів зв'яжіться з нами — ми підготуємо пропозицію під ваш проєкт.
У нас понад 100 успішних впроваджень захисту замовлень у Бітрікс. Сертифіковані спеціалісти з багаторічним досвідом. Отримайте консультацію з налаштування лімітів для вашого магазину — зв'яжіться з нами.







