Programação Por Equipe DevBras

Capa do artigo: Token do bot do Telegram: tire do código, revogue se vazou e proteja o webhook

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

  1. Leia de variável de ambiente e pare o programa com uma mensagem clara se ela não existir.
  2. Crie um .env.exemplo com o nome da variável e valor vazio, e coloque .env no .gitignore antes do primeiro commit.
  3. No servidor, use um arquivo de ambiente legível só pelo usuário do serviço.
  4. 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.

  1. No Telegram, abra o @BotFather, envie /revoke e escolha o bot. Ele gera um token novo e o antigo para de funcionar.
  2. Atualize o arquivo de ambiente do servidor e reinicie o serviço: sudo systemctl restart padaria-bot.
  3. Se usa webhook, registre-o de novo com o token novo (próxima seção).
  4. 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.
  • .env no .gitignore e .env.exemplo sem 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_token conferido 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?

Avalie este artigo

Referência: https://core.telegram.org/bots/tutorial