Безопасность28.06.2026·5 мин

Как защитить Telegram-бота: данные и DDoS

Обложка статьи "Как защитить Telegram-бота: данные и DDoS"

Бот выглядит безобиднее сайта. У него нет форм, нет открытой в интернет админки и нет страницы входа, к которой можно подобрать пароль. Именно поэтому о его защите вспоминают в последнюю очередь. Между тем у бота есть ровно то, ради чего вообще ломают: токен, база с людьми и деньги, которые через него проходят.

Токен бота

Начинается всё с токена. Токен бота фактически и является ботом, поскольку тот, у кого он есть, читает все входящие сообщения и пишет от вашего имени кому угодно. Токен не должен лежать в коде, попадать в репозиторий и светиться в логах. Держим его в переменных окружения, а файл с ними закрываем на чтение всем, кроме владельца процесса. Если токен всё-таки утёк, менять пароли бессмысленно. Токен отзывается через @BotFather, и старый мгновенно перестаёт работать.

Логи и персональные данные

Вторая по частоте утечка происходит через логи, и она же самая обидная, потому что случается без злого умысла. Разработчик пишет в лог сообщение целиком, чтобы удобнее было отлаживать, и через месяц в текстовом файле на сервере лежат телефоны, адреса и номера карт, которые люди присылали боту. Записывать в лог следует идентификатор пользователя и тип события. Содержимое сохраняем только там, где без него не разобраться, и с вырезанными чувствительными полями.

Для персональных данных работает простое правило: надёжнее всего не потерять то, что не собирал. Каждое поле, которое бот спрашивает, должно быть зачем-то нужно. Если для заявки достаточно имени и способа связи, паспортные данные и дата рождения не нужны, ведь пользы они не добавляют, а ответственности добавляют. То, что собрать всё же пришлось, шифруем и разносим: рабочая база и резервные копии не должны лежать на одном диске в открытом виде.

Админские команды и проверка подписи в WebApp

Отдельная дыра, которая встречается чаще, чем хотелось бы, это админские команды без проверки того, кто их вызвал. Кнопка "выгрузить всех пользователей" или "начислить баланс" живёт в том же боте, что и обычное меню, а разница между менеджером и посторонним умещается в одну строку кода. Список идентификаторов администраторов держим в настройках, проверку ставим на входе в обработчик, а не в середине, и обязательно дублируем её на нажатие кнопки, поскольку нажать её можно из старого сообщения.

Если у бота есть мини-приложение, добавляется проверка initData. Telegram передаёт в WebApp данные о пользователе вместе с подписью, и эту подпись нужно сверять на сервере ключом, полученным из токена бота. Без проверки любой желающий откроет ваш API и назовётся чужим идентификатором, получив вместе с ним чужие заказы и чужой баланс. Пропустить эту проверку легко, ведь без неё всё работает ровно до того дня, когда кто-нибудь попробует.

Нагрузка и ограничение частоты запросов

Теперь поговорим про нагрузку. Настоящего DDoS в привычном смысле у бота обычно не бывает, поскольку между атакующим и вами стоит Telegram, и запросы приходят с его серверов, а не напрямую. Однако перегрузить бота можно и без ботнета, для этого достаточно одного человека, зажавшего кнопку. Каждое нажатие оборачивается запросом, обращением к базе, а иногда и обращением к платному внешнему сервису, за который платите вы.

Решается это ограничением частоты на пользователя. Мы решаем, сколько действий в секунду готовы обработать от одного идентификатора, а остальное отбрасываем молча. Тяжёлые операции вроде генерации отчёта, обращения к модели или выгрузки уносим в очередь, чтобы бот отвечал сразу и не держал соединение. Обязательно подтверждаем нажатие кнопки, потому что без ответа Telegram показывает часики, человек жмёт ещё раз, и нагрузка удваивается сама собой.

Сервер, резервные копии и мониторинг

На уровне сервера действует обычная гигиена, ничего специфического для ботов здесь нет. Вход только по ключу, парольная аутентификация выключена, наружу открыт минимум портов, автоматические обновления безопасности включены. База данных слушает только localhost, ведь открытый наружу PostgreSQL находят перебором за считанные часы. Если сервисов несколько, разносим их по контейнерам, чтобы дыра в одном не открывала доступ ко всему остальному.

Резервные копии кажутся скучной темой ровно до первого случая. Копия, лежащая на том же сервере, что и база, резервной копией не является: сервер исчезает вместе с ней, и неважно, из-за сбоя диска или из-за неоплаченного счёта. Копия должна уезжать в другое место, сниматься по расписанию без участия человека и хотя бы раз быть развёрнутой обратно. Иначе неизвестно, рабочая она или это архив с ошибкой внутри.

Последний пункт заключается в том, чтобы узнавать о поломке раньше клиентов. Проверка "бот жив и отвечает" раз в минуту и уведомление в отдельный чат стоят почти ничего, а разница между "заметили за пять минут" и "заметили в понедельник" измеряется потерянными заявками. Всё перечисленное мы закладываем сразу и не продаём отдельной строкой, поскольку это не дополнительная опция, а нормальное состояние работающего сервиса.

Нужен сайт или бот?

Обсудим задачу и предложим решение под ключ.