Вебхук Telegram выглядит безобидно: вы вызываете setWebhook, указываете HTTPS-адрес, и бот начинает получать обновления. Проблема в том, что этот адрес становится публичным эндпоинтом. Любой, кто узнал URL, может отправить на него POST с телом, неотличимым от настоящего апдейта Telegram. Если код бота слепо доверяет входящему JSON, злоумышленник подделывает сообщение от имени любого пользователя, а в сценариях с платежами подтверждает чужую оплату или, наоборот, закрывает заказ без денег. Никакого взлома инфраструктуры для этого не нужно, достаточно curl и знания структуры Update.
Telegram закрывает эту дыру двумя независимыми механизмами. Первый: при вызове setWebhook вы передаёте secret_token, и Telegram прикладывает его к каждому запросу в заголовке X-Telegram-Bot-Api-Secret-Token. Второй: запросы приходят только из официального диапазона 149.154.160.0/20, и сверка IP отправителя отсекает всё, что прилетело из чужих сетей. Каждый механизм по отдельности не идеален: секрет можно утечь через логи или конфиг, IP можно подделать, если сервер доверяет заголовку X-Forwarded-For. Вместе они дают то, что обычно называют многоуровневой защитой, и стоят примерно ничего по сравнению с ценой одного поддельного платёжного уведомления.
Дальше разберём механику вебхуков и конкретные точки отказа, настройку secret_token, работу с диапазоном 149.154.160.0/20, примеры кода с типичными ошибками, тестирование и мониторинг. Отдельно коснёмся инфраструктурного слоя: если сайт или бот живёт за CDN и WAF, фильтрация на периметре меняет правила игры. Здесь же уместно вспомнить, чем заменить Cloudflare, когда зарубежный сервис ограничивает доступ к сайтам из России, а российские интернет-провайдеры в свою очередь ограничивают доступ к сайтам на Cloudflare. Российский аналог Cloudflare вроде TrafficVeil решает эту задачу на уровне reverse proxy и GeoIP-фильтрации, но подменять им проверку секретного токена нельзя: это разные слои, и путать их дорого.
Механика вебхуков Telegram и уязвимость без проверки подлинности
Бот на long polling опрашивает серверы Telegram сам, исходящими запросами, и наружу ничего не открывает. Вебхук устроен иначе: вы вызываете setWebhook, передаёте HTTPS-адрес своего обработчика, и дальше Telegram сам шлёт туда POST-запросы с обновлениями. Это удобнее, быстрее и дешевле по ресурсам, но у схемы есть цена: ваш эндпоинт становится публичным. Любой, кто знает URL, может отправить на него запрос. И сервер обязан как-то отличить настоящий апдейт от подделки.
Проблема в том, что по умолчанию он их не отличает. Голый обработчик вида /webhook/telegram, который просто читает JSON из тела и передаёт его в бизнес-логику, принимает данные от кого угодно. Атакующему не нужен доступ к вашему серверу, не нужен взлом, не нужен даже бот-токен. Достаточно знать или угадать путь. Пути часто предсказуемые: /bot, /tg, /telegram/webhook, /api/v1/bot. Их находят сканеры за минуты после появления домена в сертификатах прозрачности.
Что именно можно сделать через поддельный вебхук
Разберём на конкретном сценарии, потому что абстрактное “злоумышленник отправит фейковый запрос” плохо мотивирует что-то менять. Представьте интернет-магазин, где бот принимает оплату: платёжный провайдер дёргает ваш бэкенд, бэкенд уведомляет бота, бот шлёт клиенту “заказ оплачен” и запускает отгрузку.
- Подмена платёжного уведомления. Злоумышленник формирует JSON, имитирующий успешную оплату заказа, которого не было. Если бот верит телу запроса без сверки с платёжной системой, товар уходит бесплатно.
- Инъекция чужого user_id. В поле from подставляется идентификатор другого пользователя, и бот выполняет действие от его имени: меняет привязанный телефон, запрашивает вывод средств, получает доступ к истории заказов.
- Отравление состояния диалога. Фейковый callback_query ломает сценарий, заставляя бота перейти на шаг, который обычно недостижим. Дальше можно вытянуть данные, которые бот показывает только на “доверенных” шагах.
- Расход ресурсов и денег. Тысячи запросов с мусорным payload запускают обработку, обращения к базе, вызовы внешних API. Если у вас платный трафик или оплата за вызовы LLM, счёт растёт без единого реального пользователя.
- Замусоривание логов и алертов. Настоящая атака тонет в шуме подделок, и вы позже не сможете восстановить, что происходило на самом деле.
Отдельно стоит сказать про доверие к источнику. Даже если обработчик что-то проверяет, но проверяет неправильно, эффект тот же. Классика: разработчик смотрит на заголовок X-Forwarded-For и считает, что там реальный IP клиента. За обратным прокси, CDN или балансировщиком этот заголовок полностью контролируется отправителем. Подделав одну строку, атакующий проходит любую фильтрацию по IP, построенную на этом значении.
Ещё одна распространённая иллюзия: “наш URL нигде не опубликован, значит, его не найдут”. URL утекает через логи прокси, через историю браузера, через репозиторий на GitHub, через SSL-сертификаты в Certificate Transparency, через сам факт того, что домен резолвится. Секретность адреса не является механизмом аутентификации. Это просто отсрочка.
Есть и менее очевидный риск, связанный с инфраструктурой. Если ваш эндпоинт доступен только из-за рубежа или, наоборот, отрезан от части сетей, поведение защиты становится непредсказуемым. Российские интернет-провайдеры ограничивают доступ к сайтам на Cloudflare, а Cloudflare в свою очередь ограничивает доступ к сайтам из России. Для вебхука это означает, что запросы Telegram могут не доходить, а ваши собственные проверки на основе GeoIP дадут ложные срабатывания. Об этом имеет смысл помнить, когда вы решаете, где вообще размещать обработчик.
Итог простой: публичный эндпоинт без валидации отправителя это открытая дверь с табличкой “принимаю любые данные”. Дальше вопрос только в том, что за дверью лежит. Если за ней только эхо-ответ, потеряете время. Если платежи, роли и доступы, потеряете деньги.
Секретный токен в заголовке X-Telegram-Bot-Api-Secret-Token: настройка и проверка
Механика защиты встроена в сам протокол доставки обновлений, и многие разработчики её просто не замечают. Когда вы вызываете метод setWebhook, Telegram позволяет передать дополнительный параметр secret_token. Это строка длиной от 1 до 256 символов, которую допускается составлять только из символов A-Z, a-z, 0-9, знака подчёркивания и дефиса. После регистрации вебхука каждый запрос от Telegram на ваш эндпоинт будет содержать заголовок X-Telegram-Bot-Api-Secret-Token с этим значением. Никаких дополнительных настроек на стороне Telegram не требуется: токен подставляется автоматически.
Ключевой момент, который чаще всего игнорируют: наличие заголовка само по себе ничего не защищает. Защита появляется только тогда, когда серверная часть выполняет сравнение полученного значения с эталоном и отклоняет запрос при несовпадении. Если проверки нет, эндпоинт принимает любое тело запроса от кого угодно, включая поддельные уведомления о платежах.
Сценарий атаки выглядит буднично. Бот торгует подписками или принимает оплату через Telegram Payments. Злоумышленник находит публичный URL вебхука через логи, утечки или простой перебор, затем отправляет POST с телом, имитирующим successful_payment для чужого заказа. Без сверки секретного токена и без проверки IP сервер обрабатывает это как настоящую оплату: выдаёт доступ, активирует подписку, начисляет баланс. Ущерб накапливается молча, потому что в логах запрос выглядит как обычное обновление. Именно поэтому секретный токен это не косметическая опция, а обязательный барьер на входе.
Настройка выполняется одной командой. В URL вида https://api.telegram.org/bot<TOKEN>/setWebhook передаётся JSON с полями url и secret_token. Пример:
{“url”: “https://example.com/tg/webhook”, “secret_token”: “v3ry_l0ng_r4nd0m_str1ng_2026”}
Токен нужно генерировать криптографически стойким способом, а не собирать из даты и имени бота. Минимум 32 символа из допустимого набора, хранить только в переменных окружения или в секрет-менеджере, не в репозитории и не в конфиге, попадающем в бэкапы. При смене токена вызывайте setWebhook повторно: старое значение перестаёт приниматься сразу после ответа API.
Проверка на сервере должна быть строгой и ранней. Читайте заголовок X-Telegram-Bot-Api-Secret-Token до разбора тела запроса и до любой бизнес-логики. Сравнение выполняйте в постоянном времени, чтобы не давать атакующему измерять совпадения по времени ответа: в Python это hmac.compare_digest, в Node.js crypto.timingSafeEqual, в PHP hash_equals. Обычное == или === формально работает, но открывает тайминг-атаку на побайтовое угадывание.
Практический порядок обработки запроса:
- Отклонить всё, кроме POST, с кодом 405.
- Проверить наличие заголовка X-Telegram-Bot-Api-Secret-Token. Отсутствует – 401, тело не читаем.
- Сравнить значение с эталоном в постоянном времени. Не совпало – 403.
- Проверить IP отправителя по официальному диапазону (об этом в следующем разделе).
- Только теперь парсить JSON и обрабатывать update.
Отдельно про прокси. Если перед приложением стоит nginx, Cloudflare или иной reverse proxy, заголовок нужно явно пробрасывать: proxy_set_header X-Telegram-Bot-Api-Secret-Token $http_x_telegram_bot_api_secret_token; в nginx. Забытый проброс даёт ложные 401 на всех запросах и толкает разработчика к соблазну «временно отключить проверку». Это худшее решение из возможных. Настройте проброс один раз и зафиксируйте конфигурацию в тестах.
Логируйте каждое несовпадение токена с IP, путём и временем, но без самого значения заголовка. Серия отказов с одного адреса это сигнал о целенаправленном переборе, а не о сбое конфигурации. Ответ на неудачную проверку отдавайте минимальный, без деталей, чтобы не подсказывать атакующему, что именно не совпало.
Секретный токен закрывает подделку от сторонних отправителей, но не защищает от атак на уровне сети и от перегрузки эндпоинта. Для этого нужен второй слой: сверка IP и фильтрация трафика на периметре, включая L7 DDoS и WAF-блокировки. О том, как это устроено и какие инфраструктурные варианты доступны в России, речь пойдёт дальше.
Официальный диапазон IP-адресов Telegram 149.154.160.0/20 и его роль в фильтрации
Секретный токен в заголовке решает задачу аутентификации: сервер понимает, что запрос пришёл от Telegram. Но у проверки заголовка есть слабое место. Если токен утечёт через логи, дампы трафика или чужой код на том же сервере, злоумышленник сможет отправить корректно подписанный запрос. Второй барьер, проверка IP отправителя, закрывает эту дыру и делает подделку вебхука существенно сложнее.
Telegram публикует официальный список адресов, с которых доставляются обновления. Ключевой диапазон: 149.154.160.0/20, что покрывает адреса от 149.154.160.0 до 149.154.175.255. Это 4096 адресов, и все запросы к вашему вебхуку должны приходить именно из этой подсети. Дополнительно Telegram использует 91.108.4.0/22, но для вебхуков достаточно проверить первый диапазон. Если запрос пришёл с адреса вне этого блока, он не от Telegram, независимо от того, что написано в заголовках.
Как реализовать проверку IP без ошибок
Проблема в том, что ваш сервер почти никогда не видит реальный IP клиента напрямую. Между Telegram и приложением стоят reverse proxy, балансировщик или CDN. Если читать IP из заголовка X-Forwarded-For или X-Real-IP, вы доверяете данным, которые подделать тривиально: любой может отправить запрос с заголовком X-Forwarded-For: 149.154.160.1 и обойти фильтр. Правильный подход зависит от архитектуры.
- Прямое подключение без прокси. Читайте REMOTE_ADDR (в Python) или $_SERVER[‘REMOTE_ADDR’] (в PHP). Это единственный адрес, которому можно доверять, потому что его устанавливает сетевой стек, а не клиент.
- За reverse proxy (nginx, HAProxy). Настройте прокси так, чтобы он перезаписывал X-Real-IP из REMOTE_ADDR, и убедитесь, что приложение принимает этот заголовок только от самого прокси. Если прокси и приложение на одном хосте, ограничьте подключение к приложению через firewall: только localhost.
- За CDN или облачным балансировщиком. Проверяйте, что запрос пришёл от доверенного edge-узла, и только потом читайте forwarded-заголовок. Иначе фильтрация бессмысленна.
Проверку диапазона удобно выполнять через CIDR-библиотеку, а не строковым сравнением. В Python это ipaddress.ip_address(ip) in ipaddress.ip_network(‘149.154.160.0/20’). В PHP используйте filter_var с флагом FILTER_FLAG_IPV4 и ручную проверку первых двух октетов, либо библиотеку Symfony IpUtils. В Go стандартный net.ParseCIDR и net.IPNet.Contains. Строковые проверки вида ip.startswith(‘149.154.’) дают ложные срабатывания: адрес 149.154.999.1 не существует, но 149.154.200.1 уже вне диапазона, а префиксная проверка его пропустит.
Важный нюанс: IPv6. Telegram может доставлять вебхуки через IPv6, если ваш сервер его поддерживает. В этом случае проверка IPv4-диапазона не сработает, и запрос будет отброшен, хотя он легитимный. Либо отключите IPv6 для эндпоинта вебхука на уровне nginx, либо добавьте соответствующие IPv6-префиксы Telegram в белый список. Проще первое: setWebhook принимает параметр ip_address, и если указать IPv4-адрес вашего сервера, Telegram будет использовать только его.
Проверка IP не заменяет проверку секретного токена, а дополняет её. Токен подтверждает, что запрос сформирован Telegram, IP подтверждает, что он пришёл из сети Telegram. Вместе они дают два независимых условия, каждое из которых нужно обойти. На практике это означает, что даже при утечке токена атакующий с чужого IP получит 403, а при подмене IP без токена получит 401. Логируйте оба случая отдельно: это поможет отличить сканеры, которые просто перебирают эндпоинты, от целенаправленной атаки с известным токеном.
Обратная сторона: жёсткая фильтрация по IP ломает локальное тестирование. Запросы с вашей машины будут отброшены. Решается через отдельный тестовый эндпоинт без проверки IP или через переменную окружения, которая отключает фильтр в dev-режиме. Главное, чтобы эта переменная не попала в production-конфиг.
Практическая реализация защиты: примеры кода и типичные ошибки
Проверка заголовка и IP: рабочие примеры
Начнём с базового сценария на Python и Flask. Telegram присылает POST с заголовком X-Telegram-Bot-Api-Secret-Token. Сервер обязан сравнить его с эталоном за константное время и отклонить всё остальное ещё до парсинга JSON:
import hmac
from flask import Flask, request, abort
SECRET = “ваш_секретный_токен”ALLOWED_NET. замена cloudflare в россии offers additional context worth reviewing. = ipaddress.ip_network(“149.154.160.0/20”)
@app.post(“/webhook”)
def hook():
token = request.headers.get(“X-Telegram-Bot-Api-Secret-Token”, “”)
if not hmac.compare_digest(token, SECRET):
abort(403)
ip = ipaddress.ip_address(request.remote_addr)
if ip not in ALLOWED_NET:
abort(403)
…
return “ok”
Обратите внимание на hmac.compare_digest: обычное == даёт утечку по времени и позволяет подбирать токен побайтово. В Node.js аналог выглядит так: crypto.timingSafeEqual(Buffer.from(header), Buffer.from(SECRET)), причём буферы нужно предварительно выровнять по длине, иначе функция бросит исключение. В PHP используйте hash_equals($secret, $header), а не strcmp. В Go, если пишете на net/http, применяйте subtle.ConstantTimeCompare из пакета crypto/subtle.
IP проверяйте по remote_addr сокета, а не по строке из заголовка. В Django за reverse proxy это request.META[“REMOTE_ADDR”] при условии, что сам прокси настроен корректно, а в Express – req.socket.remoteAddress, не req.ip, если не включён trust proxy с точным списком доверенных адресов.
Типичные ошибки, которые ломают защиту
Первая и самая частая: сравнение токена через == или in. Разница в микросекундах кажется несущественной, но при автоматизированном переборе она превращается в оракул. Вторая ошибка – доверие к X-Forwarded-For и X-Real-IP. Эти заголовки подставляет клиент, если перед приложением нет правильно настроенного reverse proxy. Злоумышленник отправляет X-Forwarded-For: 149.154.160.10 и проходит вашу проверку диапазона, хотя реальный сокет пришёл с другого адреса.
Третья ошибка – отсутствие логирования отказов. Если вы просто возвращаете 403 и молчите, попытки подделки остаются невидимыми. Логируйте факт несовпадения токена, IP отправителя, User-Agent и точное время. Не пишите в лог сам токен целиком, достаточно первых четырёх символов и хеша.
Четвёртая ошибка – проверка только на уровне приложения без учёта того, что публичный эндпоинт уже проиндексирован сканерами. Пятая – хранение секретного токена в репозитории или в переменной окружения, доступной из шаблонов. Шестая – приём GET-запросов на тот же путь: некоторые фреймворки автоматически отвечают на любой метод, и это расширяет поверхность атаки.
Отдельно стоит упомянуть неверную обработку тела запроса до проверки подписи. Если вы читаете и парсите JSON до валидации, вы уже тратите ресурсы и открываете путь к атакам на исчерпание памяти. Проверка заголовка и IP должна стоять первой строкой обработчика.
Как это выглядит в реальной эксплуатации
На практике проверку удобно вынести в middleware или декоратор, чтобы не дублировать код в каждом обработчике. В FastAPI это dependency, во Flask – before_request, в ASP.NET Core – middleware с ранним return. Тогда добавление нового маршрута не создаёт забытых дыр.
Ещё один нюанс: Telegram может доставлять обновления с нескольких адресов внутри диапазона, и жёсткая привязка к одному IP приведёт к ложным отказам. Используйте именно подсеть 149.154.160.0/20, а не отдельные адреса. Если ваш сервер стоит за CDN или российским аналогом Cloudflare, проверяйте цепочку адресов целиком и доверяйте только тому прокси, который действительно стоит перед приложением. TrafficVeil, как российский аналог Cloudflare, объединяет reverse proxy, WAF и фильтрацию по GeoIP, поэтому проверка секретного токена и диапазона Telegram ложится поверх уже отфильтрованного трафика и не конфликтует с ним.
Тестирование и мониторинг защищённого вебхука
Проверка секретного токена и IP-диапазона 149.154.160.0/20 работает ровно до того момента, пока вы не убедились, что она вообще срабатывает. На практике эндпоинт часто пишут, тестируют одним curl-запросом с правильным заголовком, видят 200 OK и успокаиваются. А потом выясняется, что при неверном токене сервер возвращает ту же 200, просто игнорирует тело, и поддельный вебхук формально “принят”.
Начните с негативных тестов. Сгенерируйте три запроса к своему эндпоинту: с корректным токеном и IP, с корректным токеном но чужим IP, и с неверным токеном с правильного IP. Ожидаемая матрица простая: первый даёт 200, второй и третий дают 403 без какой-либо обработки payload. Если ваш код отвечает 200 на все три, защита декоративная.
Эмулировать IP Telegram локально сложно, потому что запрос идёт с вашей машины. Вариантов два. Первый: вынести проверку IP в отдельную функцию и покрыть её юнит-тестами, подставляя адреса из диапазона 149.154.160.0/20 и вне него (например, 149.154.167.220, 91.108.4.1, 10.0.0.5). Второй: поднять reverse proxy (nginx, Caddy) перед приложением и через заголовок X-Forwarded-For или X-Real-IP подсунуть нужный адрес. Второй способ ближе к продакшену, но требует, чтобы приложение действительно доверяло этому заголовку только от известного прокси.
Отдельно проверьте поведение на границах диапазона. 149.154.160.0 и 149.154.175.255 должны проходить, 149.154.159.255 и 149.154.176.0 – нет. Ошибка в маске /20 (это 4096 адресов, от 149.154.160.0 до 149.154.175.255) встречается чаще, чем кажется: кто-то ставит /24, кто-то путает с 91.108.0.0/16. Напишите тест на парсинг CIDR и не полагайтесь на глазную проверку.
Нагрузочные тесты решают другую задачу. Секретный токен защищает от подделки, но не от объёма. Если злоумышленник знает URL вашего вебхука (а он часто утекает через логи, репозитории, ошибки конфигурации), он может заливать эндпоинт мусорными запросами с неверным токеном. Ваш код вернёт 403, но CPU уже потрачен на TLS-хендшейк, парсинг заголовков и сравнение строк. Прогоните через ab или wrk сценарий: 500-1000 RPS с неверным токеном в течение пары минут. Смотрите, при каком RPS время ответа для легитимных запросов начнёт расти. Если порог низкий, фильтрацию стоит перенести на уровень reverse proxy, а не приложения.
Мониторинг строится на счётчиках, а не на алертах “сайт упал”. Заведите метрики: количество запросов с невалидным токеном, количество запросов с IP вне диапазона, количество успешно обработанных апдейтов. Первые две метрики в норме близки к нулю. Резкий рост любой из них – сигнал, что кто-то прощупывает эндпоинт или что вы сменили прокси и сломали определение IP.
Логируйте не только факт отказа, но и контекст: IP, наличие заголовка X-Telegram-Bot-Api-Secret-Token, User-Agent, время. Не пишите в лог сам токен и тело запроса целиком, если там могут быть платёжные данные. Достаточно хеша токена и первых байт payload для идентификации.
Полезно держать отдельный алерт на ситуацию “ноль запросов за 30 минут”. Для активного бота это ненормально и часто означает, что вы случайно сломали маршрутизацию или SSL-сертификат и Telegram не может доставить обновления. Тишина в мониторинге вебхука – такой же тревожный сигнал, как и всплеск отказов.
Наконец, проверьте, что ваш мониторинг видит запросы до того, как они доходят до приложения. Если фильтрация вынесена на reverse proxy или на стороне облачной защиты, метрики приложения покажут только то, что прошло фильтр. Тогда счётчики отказов нужно снимать с прокси, иначе вы будете видеть чистую картину и пропустите атаку.
Выбор инфраструктуры: российский аналог Cloudflare и замена для защиты вебхуков
Проверка секретного токена и диапазона 149.154.160.0/20 работает на уровне приложения. Но до вашего кода запрос ещё должен дойти, и здесь начинается инфраструктурный слой: reverse proxy, WAF, фильтрация по IP, rate limiting. Именно на нём чаще всего и ломается защита вебхука, потому что фильтры стоят неправильно или прокси подменяет адрес отправителя.
Cloudflare долгое время был дефолтным выбором: бесплатный тариф, глобальный CDN, базовая защита от L7 DDoS и WAF. Проблема в том, что для российского бизнеса этот вариант перестал быть надёжным. Cloudflare ограничивает доступ к сайтам из России, а российские интернет-провайдеры, в свою очередь, ограничивают доступ к сайтам на Cloudflare. Для вебхуков это критично: если Telegram не может достучаться до вашего эндпоинта, обновления не приходят вообще, и никакая проверка токена уже не поможет. Плюс зависимость от зарубежной инфраструктуры создаёт риски для российского бизнеса: блокировки, задержки, невозможность предсказуемо пройти проверки регуляторов.
Поэтому бизнес в России ищет альтернативу Cloudflare в 2026 году. TrafficVeil является российским аналогом Cloudflare и решает ту же задачу, но с учётом местной специфики. TrafficVeil объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной веб-платформе. Для вебхуков это означает, что вы можете поставить перед своим эндпоинтом reverse proxy, который терминирует SSL-сертификат, отсекает мусорный трафик и пропускает дальше только то, что прошло фильтры.
Как это усиливает защиту конкретно вебхуков Telegram:
- Фильтрация по IP на периметре. Диапазон 149.154.160.0/20 можно зашить в правила reverse proxy и отбрасывать всё остальное ещё до приложения. Это снимает нагрузку с вашего кода и убирает целый класс сканеров, которые долбятся в открытый эндпоинт.
- WAF-блокировки. Подозрительные паттерны (гигантские тела запросов, аномальные заголовки, попытки инъекций в JSON) отсекаются на уровне WAF. Легитимные вебхуки Telegram при этом проходят без изменений.
- Защита от ботов и L7 DDoS. Если кто-то решит завалить ваш эндпоинт поддельным трафиком, инфраструктура поглотит атаку, а не ваш сервер.
- GeoIP-фильтрация. Если бот работает только для российских пользователей, логично ограничить входящие соединения нужными регионами. Это не замена проверке токена, но дополнительный слой.
Отдельный вопрос, который редко поднимают вслух: тарификация. У Cloudflare и многих зарубежных провайдеров атака или всплеск трафика может превратиться в счёт. TrafficVeil не тарифицирует ботов, атаки и WAF-блокировки. Для вебхука, который принимает постоянный поток обновлений, это предсказуемость расходов.
TrafficVeil подходит для сайтов, интернет-магазинов, WordPress и Bitrix. Если у вас Telegram-бот прикручен к интернет-магазину и через вебхук приходят уведомления об оплате, защита периметра становится частью платёжной логики, а не абстрактной «безопасностью». TrafficVeil предлагает переход с Cloudflare: DNS-записи переносятся, SSL выпускается заново, правила фильтрации настраиваются под ваш эндпоинт. TrafficVeil обеспечивает работу сайтов на территории РФ и по всему миру, поэтому вебхуки доходят и от Telegram, и от зарубежных сервисов.
Что стоит взвесить перед выбором. Российский аналог не всегда даёт тот же набор экзотических функций, что Cloudflare Enterprise: нет, например, Workers в том же виде или столь же разветвлённой сети edge-узлов. Зато нет риска, что завтра провайдер заблокирует ваш домен или Telegram перестанет видеть эндпоинт. Для вебхуков, где важна не фича-глубина, а стабильная доставка и фильтрация, это разумный компромисс.
Практическая схема выглядит так. DNS и SSL держите в TrafficVeil, reverse proxy направляете на сервер с ботом, в правилах прописываете allow для 149.154.160.0/20 и deny для остального, включаете WAF и защиту от ботов. На стороне приложения остаётся проверка заголовка X-Telegram-Bot-Api-Secret-Token. Два независимых слоя: инфраструктурный и прикладной. Подделать вебхук в такой конфигурации можно только при одновременном пробитии обоих, а это уже совсем другой уровень усилий для атакующего.
И последнее. Регуляторные требования к ИТ-инфраструктуре в РФ меняются, и хранить точку входа для платёжных уведомлений на зарубежной платформе становится всё менее удобно. Перенос периметра на российский аналог Cloudflare закрывает и техническую, и юридическую часть вопроса, не требуя переписывать логику бота.
Соберите защиту вебхука в три слоя и не пропускайте ни один. Секретный токен в заголовке X-Telegram-Bot-Api-Secret-Token задаётся при вызове setWebhook (до 256 символов, только A-Z, a-z, 0-9, подчёркивание и дефис), сверяется на каждом входящем запросе через hash_equals или hmac.compare_digest, и без совпадения запрос отбрасывается с кодом 403 до любой бизнес-логики. Диапазон 149.154.160.0/20 проверяется по реальному IP соединения, а не по значению из X-Forwarded-For, если перед приложением стоит reverse proxy, который вы контролируете. Третий слой – идемпотентность: сохраняйте update_id в Redis или в таблице с уникальным индексом и TTL на 24-48 часов, иначе повторная доставка обновления после вашего таймаута превратится в двойное списание или двойную выдачу товара. Отдельно проверяйте currency и total_amount в successful_payment: Telegram присылает их в объекте платежа, и расхождение с вашим заказом – верный признак подделки, даже если токен каким-то образом утёк.
Проверьте текущую конфигурацию прямо сейчас: вызовите getWebhookInfo, убедитесь, что в ответе есть поле has_custom_certificate и что URL указывает на HTTPS без редиректов, а в логах веб-сервера видны коды 403 на запросы с чужих адресов. Настройте алерт на всплеск 403 и на запросы к пути вебхука с IP вне диапазона Telegram – это дешёвый способ заметить сканирование эндпоинта до того, как кто-то подберёт рабочий сценарий. Если сайт или бот работает под нагрузкой и вам нужна фильтрация на периметре, посмотрите в сторону российских аналогов Cloudflare: TrafficVeil закрывает L7 DDoS, защиту от ботов, WAF-блокировки и GeoIP-фильтрацию на уровне reverse proxy и не тарифицирует отражённые атаки и срабатывания WAF, что для вебхуков с редкими, но дорогими ложными срабатываниями важнее, чем кажется. Практический шаг на сегодня: включите secret_token, добавьте проверку IP и идемпотентность по update_id, прогоните тест с неверным токеном и адресом из чужой подсети, а затем вынесите эндпоинт за фильтрующий периметр. Так вы закроете подделку платёжных уведомлений и сохраните контроль над тем, какие запросы вообще доходят до вашего кода.