Как блокировать VPN, прокси и Tor-трафик
Рабочие правила для Cloudflare WAF, Nginx, Caddy и Stripe Radar. Плюс плейбук по ложным срабатываниям. Большая часть VPN-трафика это легитимные пользователи, поэтому грубая блокировка оборачивается потерей клиентов. Используйте эти паттерны там, где трение реально окупается.
Решение: где блокировать, где усиливать
- Блокировать: создание аккаунтов, отправка KYC, вывод средств (withdrawal, refund), админские и служебные маршруты.
- Усилить аутентификацию: логин, сброс пароля, оплата, изменение подписки, массовые операции.
- Разрешать: чтение контента, RSS, публичная документация. Жёсткая блокировка этих маршрутов теряет больше денег, чем предотвращает.
Выражение Cloudflare WAF
Встроенные cf.threat_score и ip.src.is_in_european_union сами по себе ловят слишком мало. Добавьте внешний lookup через Cloudflare Worker (см. руководство по внедрению), затем применяйте правило WAF:
# Блокировать VPN/прокси на регистрации и оплате
(http.request.uri.path matches "^/(signup|checkout|api/payment)" and
cf.threat_score gt 14 or
ip.src.is_in_european_union eq false and any(http.request.headers["x-iplogs-verdict"][*] in {"vpn_detected" "vpn_likely"}))Заголовок x-iplogs-verdict ставится из Worker, который вызывает POST /v1/check для IP посетителя.
Nginx: блок по списку ASN
Для статической блокировки по ASN скачайте CSV от IPLogs в /data/datacenter-asns.csv и сконвертируйте в geo-блок Nginx:
# Сгенерируйте /etc/nginx/conf.d/vpn-block.conf из списка ASN от IPLogs
geo $is_vpn_asn {
default 0;
# Добавьте CIDR-диапазоны для AS9009 (M247), AS62240 (Clouvider) и т.д.
# Источник: https://iplogs.com/data/datacenter-asns.csv
23.234.0.0/16 1;
185.65.0.0/16 1;
# ...
}
server {
location ~ ^/(signup|checkout) {
if ($is_vpn_asn) {
return 403 "VPN traffic blocked on this route";
}
proxy_pass http://app;
}
}Caddy: блок по заголовку через reverse-proxy
# Сниппет Caddyfile. Вердикт ставится из плагина Caddy,
# либо из middleware вашего приложения до reverse-proxy.
example.com {
@vpn_block {
path /signup* /checkout*
header X-IPLogs-Verdict vpn_detected vpn_likely
}
respond @vpn_block 403 "VPN traffic blocked on this route"
reverse_proxy localhost:3000
}Stripe Radar: рецепт правила
Stripe Radar 2.0 уже по умолчанию помечает VPN/прокси как повышенный риск. Чтобы применять более жёсткие правила, передайте вердикт IPLogs в Customer.metadata при создании payment intent:
// При создании payment intent
const verdict = (await checkVpn(customerIp)).verdict;
await stripe.paymentIntents.create({
amount, currency,
customer: customerId,
metadata: { iplogs_verdict: verdict },
});
// Правило в Stripe Radar (UI):
// Block if :metadata:iplogs_verdict: == "vpn_detected"
// Review if :metadata:iplogs_verdict: == "vpn_likely"
// 3DS if :metadata:iplogs_verdict: == "suspicious" and :amount: > 5000Плейбук по ложным срабатываниям
Перед тем как блокировать, продумайте обработку ложных срабатываний. Большинство жалоб на FP приходит от этих категорий:
- CGNAT и мобильные операторы разделяют пулы IP между тысячами абонентов, и эти диапазоны нередко пересекаются с коммерческими VPN-выходами. Лучше усиливать аутентификацию, а не блокировать.
- Cloudflare WARP и iCloud Private Relay включены у миллионов пользователей по умолчанию. Выделите их в отдельный класс
private_relayи применяйте к ним заметно меньшее трение. - Корпоративные прокси: крупные клиенты направляют весь трафик через единый egress, который выглядит как датацентровый выход.
- Путешествующие сотрудники: бизнес-пользователи рутинно поднимают рабочий VPN из командировок, и именно это самые ценные клиенты, которых легче всего ошибочно заблокировать.
Всегда оставляйте путь оспаривания. Сообщение «обнаружен VPN, попробуйте другую сеть» со ссылкой на форму контакта возвращает часть выручки, потерянной из-за ложных срабатываний.
Сначала встраиваете обнаружение в код? Смотрите руководство по внедрению. Хотите понять, почему ваш собственный IP помечен как VPN? Прочтите разбор причин.