Налаштування захисту контенту від парсингу 1С-Бітрікс
Конкуренти парсять каталог: збирають ціни, описи, характеристики, використовують для моніторингу або копіюють на власний сайт. Повний захист неможливий — якщо людина може бачити дані, програма теж може. Завдання — зробити парсинг достатньо дорогим, щоб він втратив економічний сенс.
Ешелонований захист
Захист будується в кілька шарів. Кожен шар ловить різний тип парсерів.
Шар 1 — nginx rate limiting. Перший рубіж, не навантажує PHP:
# /etc/nginx/conf.d/rate-limit.conf
# Зона для обмеження по IP
limit_req_zone $binary_remote_addr zone=catalog:10m rate=20r/m;
limit_req_zone $binary_remote_addr zone=search:10m rate=5r/m;
# Застосовуємо до сторінок каталогу
location /catalog/ {
limit_req zone=catalog burst=40 nodelay;
limit_req_status 429;
# ... інші директиви
}
location /search/ {
limit_req zone=search burst=10 nodelay;
limit_req_status 429;
}
Шар 2 — аналіз User-Agent. У 1С-Бітрікс через init.php:
// /local/php_interface/init.php
$blockedAgents = [
'python-requests', 'scrapy', 'curl/', 'wget/',
'Go-http-client', 'Java/', 'PhantomJS', 'Headless',
];
$ua = strtolower($_SERVER['HTTP_USER_AGENT'] ?? '');
foreach ($blockedAgents as $bad) {
if (str_contains($ua, strtolower($bad))) {
header('HTTP/1.1 403 Forbidden');
exit;
}
}
Примітивні парсери відсіюються одразу. Просунуті підміняють User-Agent — використовуємо наступні шари.
Шар 3 — поведінковий аналіз. Реальні користувачі не запитують 200 сторінок каталогу за 5 хвилин. Лічильник запитів по IP в Redis:
namespace Local\Security;
class RateLimiter
{
private const WINDOW = 300; // 5 хвилин
private const LIMIT = 100; // запитів на каталог
private const BAN_TIME = 3600; // бан на годину
public static function check(string $ip): bool
{
$redis = \Bitrix\Main\Data\Cache::createInstance();
// Спрощено: використовуємо кеш 1С-Бітрікс
$key = 'ratelimit_catalog_' . md5($ip);
$count = (int)(\Bitrix\Main\Application::getInstance()
->getManagedCache()->get($key) ?? 0);
if ($count > self::LIMIT) {
// Логуємо і блокуємо
self::banIp($ip);
return false;
}
\Bitrix\Main\Application::getInstance()->getManagedCache()->set(
$key,
$count + 1,
self::WINDOW
);
return true;
}
private static function banIp(string $ip): void
{
// Додаємо до таблиці банів 1С-Бітрікс (b_stop_list)
\CStopList::Add([
'SITE_ID' => SITE_ID,
'IP_ADDR' => $ip,
'ACTIVE' => 'Y',
'REASON' => 'Автоматичний бан: підозра на парсинг',
]);
}
}
Шар 4 — CAPTCHA на підозрілих запитах. Коли лічильник наближається до 70% від ліміту — показуємо challenge замість контенту. У 1С-Бітрікс інтеграція через Cloudflare Turnstile або вбудований механізм капчі.
Захист цін через JavaScript
Ціни виводяться не в HTML, а завантажуються через AJAX після рендеру сторінки. Прості HTML-парсери отримують сторінку без цін:
// У шаблоні картки товару замість ціни:
<span class="product-price js-price-loader" data-product-id="<?= $arResult['ID'] ?>">
<span class="skeleton">----</span>
</span>
// Після DOMContentLoaded завантажуємо ціни
const priceElements = document.querySelectorAll('.js-price-loader');
if (priceElements.length) {
const ids = [...priceElements].map(el => el.dataset.productId);
fetch('/local/ajax/prices.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
body: JSON.stringify({ ids }),
})
.then(r => r.json())
.then(data => {
priceElements.forEach(el => {
const price = data.prices[el.dataset.productId];
if (price) el.innerHTML = price.formatted;
});
});
}
Headless-браузери (Playwright, Puppeteer) це долають, але потребують значно більше ресурсів на парсинг — вартість зростає.
Honeypot-посилання
Приховані посилання в HTML, невидимі для людей (display: none), але індексовані парсерами:
<a href="/honeypot/trap-page/?ref=bot" style="display:none" aria-hidden="true"><!-- noindex --></a>
// /honeypot/trap-page/index.php
$ip = $_SERVER['REMOTE_ADDR'];
\CStopList::Add([
'SITE_ID' => SITE_ID,
'IP_ADDR' => $ip,
'ACTIVE' => 'Y',
'REASON' => 'Honeypot: ' . $_SERVER['REQUEST_URI'],
]);
// Віддаємо нескінченний потік сміттєвих даних або 403
header('HTTP/1.1 403 Forbidden');
Захист зображень через X-Accel-Redirect
Зображення віддаються через PHP з перевіркою, а nginx виконує ефективну віддачу файлу:
location /protected-uploads/ {
internal; # недоступно напряму ззовні
alias /var/www/upload/;
}
header('X-Accel-Redirect: /protected-uploads/' . $relativePath);
header('Content-Type: image/jpeg');
exit;
Що обрати для конкретного проекту
| Загроза | Рішення | Складність |
|---|---|---|
| Простий curl/wget парсер | nginx rate limit + UA фільтр | Низька |
| Парсер з імітацією браузера | Rate limit + поведінковий аналіз | Середня |
| Headless браузер | JS-завантаження цін + CAPTCHA | Висока |
| Промисловий парсинг | Cloudflare Bot Management | Потребує CDN |
Rate limiting + UA фільтр + honeypot відсікають 90% нецільових парсерів за 1–2 дні роботи.







