Налаштування лімітів замовлень за 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 успішних впроваджень захисту замовлень у Бітрікс. Сертифіковані спеціалісти з багаторічним досвідом. Отримайте консультацію з налаштування лімітів для вашого магазину — зв'яжіться з нами.







