Token do bot do Telegram: tire do código, revogue se vazou e proteja o webhook
Guarde o token do bot em variável de ambiente, revogue no BotFather quando ele vazar, procure tokens no histórico do Git e confira o segredo de cada chamada do webhook.
O bot da padaria responde "Bom dia, seu pedido foi anotado" e você comemora. O token que o BotFather entregou está na linha 3 do bot.py, e o git push para o repositório público aconteceu dez minutos depois. Robôs varrem o GitHub atrás de exatamente esse padrão de texto. A resposta curta: quem tem o token é o bot, então ele vive em variável de ambiente, nunca no código; se já foi para o Git, revogue no BotFather antes de qualquer outra coisa; e, se você usa webhook, configure um segredo para recusar chamadas que não vêm do Telegram.
O exemplo deste guia é esse bot de pedidos, @padaria_central_bot, em Python, rodando num servidor pequeno com systemd. Os mesmos passos valem para Node, .NET ou qualquer linguagem.
Por que o token vale tanto
A API de bots do Telegram autentica pelo token na própria URL: https://api.telegram.org/bot<token>/sendMessage. Não há usuário, senha nem segundo fator. Com o token, qualquer pessoa pode mandar mensagem a todos que já falaram com o seu bot, trocar o webhook para um servidor dela e passar a receber os pedidos dos seus clientes, ou apagar a configuração.
O formato é fácil de reconhecer: o número do bot, dois-pontos e uma sequência longa de letras, números, hífen e sublinhado. Por isso o vazamento é encontrado rápido por quem procura. E como o token vai na URL, ele também aparece em lugares menos óbvios: logs de requisição de bibliotecas HTTP, histórico do terminal e mensagens de erro com o endereço completo.
Como tirar o token do código
- Leia de variável de ambiente e pare o programa com uma mensagem clara se ela não existir.
- Crie um
.env.exemplocom o nome da variável e valor vazio, e coloque.envno.gitignoreantes do primeiro commit. - No servidor, use um arquivo de ambiente legível só pelo usuário do serviço.
- Nunca registre a URL completa da API em log. Registre o método chamado, não o endereço.
# bot.py
import os
import sys
import requests
TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN")
if not TOKEN:
sys.exit("defina TELEGRAM_BOT_TOKEN no ambiente")
API = "https://api.telegram.org/bot" + TOKEN
def chamar(metodo, **dados):
r = requests.post(API + "/" + metodo, json=dados, timeout=15)
if not r.ok:
# não imprime r.url: ela contém o token
print("falha em", metodo, r.status_code)
return r.json()
if __name__ == "__main__":
eu = chamar("getMe")
print("conectado como", eu["result"]["username"])
# .gitignore
.env
# .env.exemplo (este vai para o Git)
TELEGRAM_BOT_TOKEN=
TELEGRAM_WEBHOOK_SECRET=
# /etc/systemd/system/padaria-bot.service (trecho)
[Service]
User=padariabot
EnvironmentFile=/etc/padaria-bot/env
ExecStart=/opt/padaria-bot/venv/bin/python /opt/padaria-bot/bot.py
sudo chown root:padariabot /etc/padaria-bot/env
sudo chmod 640 /etc/padaria-bot/env
Se você usa uma biblioteca de bot, confira o nível de log do cliente HTTP dela. Algumas registram cada requisição com a URL em nível informativo, e a URL carrega o token. Suba o nível desse logger para aviso em produção.
Se o token já foi para o Git
A ordem importa. Primeiro troque, depois limpe. Limpar o histórico com o token ainda válido não adianta: forks, clones e caches já têm a cópia.
- No Telegram, abra o
@BotFather, envie/revokee escolha o bot. Ele gera um token novo e o antigo para de funcionar. - Atualize o arquivo de ambiente do servidor e reinicie o serviço:
sudo systemctl restart padaria-bot. - Se usa webhook, registre-o de novo com o token novo (próxima seção).
- Só então remova o token do histórico, se ainda quiser; o passo a passo e os cuidados com a equipe estão em segredo no Git se troca antes de limpar.
Para descobrir se há outros tokens perdidos no repositório, procure o padrão no código atual e em todo o histórico:
git grep -nE '[0-9]{8,12}:[A-Za-z0-9_-]{30,}'
git log -p --all | grep -nE '[0-9]{8,12}:[A-Za-z0-9_-]{30,}'
Ferramentas como o gitleaks fazem essa varredura com regras para muitos tipos de segredo e podem rodar num hook de pré-commit e no CI, que é onde o próximo vazamento deveria ser barrado.
Como proteger o webhook
Com webhook, o Telegram chama uma URL sua a cada mensagem. Qualquer pessoa que descubra essa URL pode mandar um "pedido" falso. O setWebhook aceita um parâmetro secret_token, e o Telegram passa a enviar esse valor no cabeçalho X-Telegram-Bot-Api-Secret-Token de cada chamada. O seu servidor recusa o que não trouxer o valor certo.
# gerar o segredo (letras, números, hífen e sublinhado)
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# registrar o webhook lendo token e segredo do ambiente
curl -s "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/setWebhook" -d url=https://bot.padaria.exemplo/telegram -d secret_token="$TELEGRAM_WEBHOOK_SECRET"
# webhook.py (Flask)
import hmac
import os
from flask import Flask, abort, request
app = Flask(__name__)
SEGREDO = os.environ["TELEGRAM_WEBHOOK_SECRET"]
@app.post("/telegram")
def receber():
recebido = request.headers.get("X-Telegram-Bot-Api-Secret-Token", "")
if not hmac.compare_digest(recebido, SEGREDO):
abort(403)
update = request.get_json(silent=True) or {}
registrar_pedido(update)
return "", 200
O compare_digest compara em tempo constante, sem dar pista de quantos caracteres acertaram. O Telegram também pode reenviar a mesma atualização se a sua resposta demorar; use o update_id para não registrar o pedido duas vezes, como em webhook com segredo e evento repetido.
Depois de registrar, confira com o método getWebhookInfo: ele mostra a URL ativa, quantas atualizações estão pendentes e a última mensagem de erro de entrega. Se a URL ali não for a sua, alguém com o token antigo chegou antes, e o /revoke é urgente. Repita essa conferência sempre que trocar de servidor ou de token.
Erros comuns
- Token no código "só até funcionar". O primeiro push leva junto, e repositório público é varrido em minutos.
- Apagar o commit e achar que resolveu. O token continua válido e as cópias continuam existindo. Sem
/revoke, nada mudou. - Imprimir a URL da API no log. O token passa a morar em todo arquivo de log, backup de log e painel de monitoramento.
- Webhook sem
secret_token. Qualquer um com a URL injeta mensagens como se fossem de clientes. - Arquivo de ambiente legível por todos. Qualquer usuário ou processo do servidor lê o token.
- Bot em long polling num notebook. O notebook dorme, o bot para de responder e parece bug. Bot de produção roda em servidor.
Checklist
- Token lido de
TELEGRAM_BOT_TOKEN, sem valor no código. .envno.gitignoree.env.exemplosem valores.- Busca pelo padrão de token no código e no histórico sem resultado.
- Arquivo de ambiente no servidor com permissão restrita ao serviço.
- Nenhum log com a URL completa da API.
- Webhook com
secret_tokenconferido em toda chamada. - Varredura de segredos no pré-commit ou no CI.
Rode agora o git log -p --all com o padrão acima no repositório do seu bot. Se aparecer um valor, revogue antes de terminar de ler o resultado. E a pergunta que define o tamanho do problema: o repositório é público, ou quantas pessoas o clonaram desde aquele commit?
Referência: https://core.telegram.org/bots/tutorial