Разработка · 7 мин чтения

Токен Telegram-бота: где взять, как хранить и что делать при утечке

Токен Telegram-бота - это единственная строка, которая отличает ваш бот от чужого. Тот, кто её получает, может слать сообщения от имени бота, менять вебхук, читать апдейты из всех чатов, куда бот добавлен, и удалить бота вовсе. При этом токен на практике почти всегда оказывается там, где ему быть не следует: в публичном репозитории на GitHub, в скриншоте для техподдержки, в логах CI или прямо в коде фронтенда. Разбираю, где токен получить, как хранить его в проекте на PHP или Python и что делать, если он всё-таки утёк.

Где взять токен Telegram-бота

Токен выдаёт официальный бот BotFather, и другого легального способа его получить нет. Процесс:

  • Открываете чат с @BotFather и отправляете команду /newbot
  • Указываете отображаемое имя бота, любое, можно на русском
  • Указываете username бота, он обязательно должен заканчиваться на bot, например my_shop_bot
  • BotFather присылает токен в первом же ответном сообщении

Это сообщение единственный момент, когда токен показывается в чистом виде без лишних действий, поэтому его сразу нужно сохранить в менеджере паролей или в переменных окружения проекта, а не оставлять висеть в переписке.

Если бот уже создан и токен потерян, доставать его заново тоже надо через BotFather: команда /mybots, выбор нужного бота из списка, кнопка «API Token». Там же лежит кнопка «Revoke current token» - она пригодится в разделе про утечку.

Из чего состоит токен и почему его нельзя путать с другими ключами

Токен выглядит так: 123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw. Первая часть до двоеточия - это числовой ID бота, он не секретный и виден в любом апдейте, который приходит на вебхук. Вторая часть после двоеточия - это и есть секрет, примерно 35 символов, именно её нельзя светить нигде.

В проектах вокруг ботов встречается ещё несколько похожих по смыслу, но других по назначению значений, и путать их с токеном бота не стоит:

  • секретный токен вебхука (secret_token в методе setWebhook) - отдельная строка, которую вы сами придумываете для проверки входящих запросов
  • initData мини-приложения - подписанные данные о пользователе, которые проверяются HMAC с использованием токена бота, но сами по себе токеном не являются
  • токены платёжных провайдеров, которые подключаются через BotFather для приёма оплаты внутри бота, это отдельный секрет конкретной платёжной системы

Куда токен нельзя класть ни при каких обстоятельствах

Самые частые способы слить токен, с которыми сталкиваюсь на реальных проектах:

  • захардкодить в коде и закоммитить в git, включая приватный репозиторий - доступ к приватному репо со временем расширяется на подрядчиков и CI-системы, а токен там остаётся навсегда в истории коммитов
  • вставить в JS-код на фронтенде или в скрипт на Tilda - весь клиентский код виден в браузере через «Просмотр кода страницы»
  • прислать в переписке в мессенджере или тикете техподдержки текстом, а не через защищённый канал
  • оставить в Dockerfile через ARG или ENV с конкретным значением - слой образа с секретом остаётся в истории образа даже после удаления файла в следующем слое
  • показать на скриншоте консоли или .env файла в статье, презентации или демо для клиента

Как хранить токен бота на практике

Конкретный способ зависит от того, где живёт бот.

Если бот работает через вебхук и весь его код это один HTTP-обработчик, для такой задачи не нужен отдельный сервер, обычного хостинга с PHP достаточно. Токен кладу в .env-файл вне корня сайта или защищаю его через .htaccess, а в коде читаю через getenv() либо через библиотеку вроде vlucas/phpdotenv. Ключевое правило: .env обязательно идёт в .gitignore и никогда не попадает в репозиторий.

<?php
require __DIR__ . '/vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

$botToken = $_ENV['TG_BOT_TOKEN'];
$apiUrl = "https://api.telegram.org/bot{$botToken}/sendMessage";

Если бот сложнее и держит состояние, память диалогов, очередь задач или интеграции с внешними API, такие вещи обычно пишу на aiogram (Python), а сам процесс держу на VPS под systemd или в Docker-контейнере. В этом случае токен передаю через переменные окружения systemd-юнита (директива EnvironmentFile=) или через --env-file у Docker, и читаю в коде через os.environ, а не через строку с готовым значением в файле бота. Здесь важна оговорка: это отдельный сервер, который требует настройки, обновлений и ежемесячной оплаты, в отличие от обычного хостинга сайта.

Если бот подключён через n8n, например как триггер для уведомлений о заказах, токен не нужно вставлять вручную в URL HTTP-ноды - в n8n есть встроенное хранилище credentials именно для Telegram-ноды, значение там не светится в логах выполнения workflow.

Способ хранения Где применяю Риск утечки
Переменные окружения хостинга или сервера PHP-обработчик вебхука, aiogram-бот на VPS Низкий
.env файл вне git с .gitignore Локальная разработка, тестовый стенд Низкий, если .gitignore настроен верно
Secrets в GitHub Actions или другой CI Автодеплой бота Низкий
Встроенное хранилище credentials в n8n Telegram-триггеры и уведомления в n8n Низкий
Прямо в коде или в конфиге, закоммиченном в репозиторий Не делаю так Высокий

Если бот тянет на полноценный сервис с оплатой, личным кабинетом или интеграцией с CRM, разумнее сразу заказать разработку Telegram-бота с продуманной схемой хранения секретов, чем потом переносить токен из захардкоженного кода в переменные окружения на живом проекте.

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

Что делать, если токен бота утёк

Признаки, что токен попал не в те руки: бот рассылает сообщения, которые вы не отправляли, в getWebhookInfo стоит незнакомый URL вебхука, появляются логи запросов к Bot API с чужого IP или пользователи жалуются на спам от бота.

Порядок действий:

  1. Иду в @BotFather, команда /mybots, выбираю бота, открываю «API Token», нажимаю «Revoke current token». Старый токен перестаёт работать мгновенно, BotFather сразу выдаёт новый
  2. Обновляю новый токен во всех местах, где он использовался: переменные окружения на сервере, secrets в CI, credentials в n8n, конфиг локальной разработки
  3. Заново регистрирую вебхук на новый токен через метод setWebhook, старый вебхук был привязан к отозванному токену и всё равно перестал бы принимать апдейты
  4. Если токен попадал в git, отзыва токена недостаточно для чистоты истории: сам файл с секретом остаётся в старых коммитах и будет найден ботами, которые сканируют публичные репозитории. Историю нужно переписать или, если репозиторий приватный и утечка не подтверждена, как минимум убедиться, что доступ к нему ограничен
  5. Проверяю, что успел сделать чужой токен: смотрю список команд бота, настройки вебхука, список администраторов в группах, куда добавлен бот

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

Секретный токен вебхука и другие меры защиты

Отдельно от токена бота у Bot API есть параметр secret_token в методе setWebhook. Это строка, которую придумываете сами, Telegram передаёт её в заголовке X-Telegram-Bot-Api-Secret-Token при каждом запросе на ваш вебхук, и по ней можно отличить настоящий запрос от Telegram от подделанного запроса на тот же URL.

curl -F "url=https://example.com/webhook.php" \
     -F "secret_token=$TG_WEBHOOK_SECRET" \
     "https://api.telegram.org/bot$TG_BOT_TOKEN/setWebhook"

На стороне обработчика проверка выглядит так:

<?php
$secret = $_SERVER['HTTP_X_TELEGRAM_BOT_API_SECRET_TOKEN'] ?? '';

if (!hash_equals(getenv('TG_WEBHOOK_SECRET'), $secret)) {
    http_response_code(403);
    exit;
}

hash_equals сравнивает строки за постоянное время и специально существует для таких проверок, обычное сравнение через == для секретов лучше не использовать.

Ещё несколько практик, которые снижают ущерб от возможной утечки:

  • для команд администратора в коде бота всегда сверяю chat_id или user_id отправителя со списком разрешённых ID, а не полагаюсь на то, что о существовании команды никто не узнает
  • для ботов с приёмом оплаты или доступом к персональным данным периодически меняю токен через тот же Revoke, даже без признаков утечки
  • токен бота нигде не передаю в JS мини-приложения, вся логика с подписью initData и обращениями к Bot API остаётся на сервере

Условия и возможности Telegram меняются, поэтому перед запуском я уточняю их у самого сервиса.

Частые вопросы

Можно ли получить токен бота без BotFather?

Нет, BotFather - единственный официальный источник токена, он же официальный бот Telegram для управления ботами. Любые сервисы, предлагающие «выдать токен» в обход него, не имеют отношения к Bot API.

Как понять, что токен бота утёк?

Косвенные признаки: бот отправляет сообщения, которые вы не инициировали, в ответе метода getWebhookInfo появляется незнакомый URL, в логах сервера видны запросы к Bot API с адресов, которых у вас нет в инфраструктуре, либо пользователи сообщают о спаме от бота.

Нужно ли менять токен, если бот работает через вебхук, а не через polling?

Это не зависит от способа получения апдейтов. И вебхук, и polling используют один и тот же токен для авторизации в Bot API, поэтому правила хранения и порядок действий при утечке одинаковы для обоих вариантов.

Что происходит с ботом, пока я жду и подключаю новый токен после отзыва?

Старый токен перестаёт работать сразу после нажатия «Revoke current token» в BotFather, новый токен BotFather выдаёт в том же сообщении. Пока новый токен не прописан в коде и вебхук не переустановлен под него, бот не обрабатывает сообщения, поэтому обновление стоит делать сразу вслед за отзывом, без паузы.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно