TIPS 23 · CHIAVI

A chave no código

O prompt que procura chaves e palavras-passe no código e no histórico do git, como as passar para o .env, e o que fazer se já te fugiu uma.

O que é e porque importa

Quando ligas um serviço à tua app, como uma base de dados, os pagamentos ou uma IA, dão-te uma chave. É uma sequência longa, e o mais cómodo é colá-la diretamente no código. Se a passares ao Claude no chat sem lhe dizer onde a pôr, às vezes ele também faz isso.

O problema é onde o código vai parar. Se o carregas no GitHub, a chave viaja com ele. Num repositório público qualquer pessoa a pode ler, e há programas que correm de propósito para apanhar chaves assim que aparecem. Quem a encontra usa-a em teu nome.

E apagá-la do código não chega. O git guarda a história toda: se a chave esteve num commit, nem que seja um só, nem que seja de há meses, continua lá. Quem descarrega o repositório volta a encontrá-la.

Nem todas as chaves são secretas. A pública do Supabase ou do Firebase é feita para estar na app: falo disso no guia PORTA (strikt.fit/porta). Aqui falo das outras: a chave secreta da base de dados, a da IA, a dos pagamentos, a dos emails. Essas ficam só no servidor, como no guia LIMITE (strikt.fit/limite).

1. A verificação

Antes de corrigir, vê o que lá está. Abre o Claude Code na pasta do projeto e cola:

O prompt
Procura no projeto e em todo o histórico do git chaves, tokens e palavras-passe escritos no código, também nos ficheiros de configuração e nos commits antigos. Para cada um diz-me ficheiro, linha (ou commit) e serviço. Nunca mostres o valor.

«Todo o histórico», senão o Claude só olha para os ficheiros de agora. «Nunca mostres o valor», porque te basta saber onde está: a chave não deve aparecer no chat.

Uma segunda opinião: gitleaks

Um programa feito de propósito reconhece a forma de muitíssimos tipos de chave. Eu uso o gitleaks, que é open source. No Mac instalas com o Homebrew:

A linha
brew install gitleaks

Depois, dentro da pasta do projeto:

Os comandos
gitleaks git -v --redact
gitleaks dir -v --redact
  • gitleaks git analisa todo o histórico, commit a commit.
  • gitleaks dir analisa os ficheiros de agora, também os que o git não segue.
  • --redact esconde os valores nos resultados, -v mostra os detalhes.

No GitHub

Nos repositórios públicos o secret scanning do GitHub é gratuito e automático: se encontra a chave de um serviço que conhece, põe um alerta no separador Security and quality. A push protection vai mais longe: bloqueia o push que leva uma chave, antes de chegar à internet. Para os teus próprios push para repositórios públicos está ativa por predefinição; no repositório ativas em Settings → Advanced Security. Nos repositórios privados poderá exigir uma funcionalidade paga do GitHub.

2. As chaves no .env

O sítio certo para uma chave é um ficheiro .env que o git nunca carrega. Funciona assim:

  1. As chaves vão num ficheiro .env na pasta do projeto: NOME_CHAVE=valor.
  2. No ficheiro .gitignore acrescenta a linha .env: o git nunca o carrega.
  3. No código fica só o nome: process.env.NOME_CHAVE (o teu framework ou o dotenv lê o ficheiro).
  4. Onde publicas a app, as mesmas variáveis vão nas definições do alojamento.

O prompt para o Claude o fazer:

O prompt
Tira as chaves do código: põe-nas no .env, acrescenta .env ao .gitignore, cria um .env.example só com os nomes e verifica que nenhuma chave secreta acaba no código do browser.

O .env.example, esse sim, carregas: só tem os nomes, tipo AI_API_KEY= sem nada a seguir. Assim, mais à frente, tu e quem trabalha contigo sabem que chaves são precisas sem ver nenhuma.

Se o .env já estava no repositório

O .gitignore só vale para os ficheiros que o git ainda não segue. Se o .env já tinha sido carregado, o .gitignore não chega: corre git rm --cached .env, que o tira do repositório e o deixa no computador, e depois faz um commit. A seguir muda as chaves que lá estavam, porque ficam no histórico: vê a parte 4. Se quiseres, pede ao Claude para o fazer e te explicar cada passo.

3. As variáveis que vão parar ao browser

É aqui que mais se cai. Pôr uma chave no .env não a torna secreta: o que conta é onde corre o código que a usa. O que corre no servidor continua a ser teu. O que chega ao browser, ou à app no telemóvel, qualquer pessoa vê, com .env ou sem ele.

Alguns frameworks mandam de propósito para o browser as variáveis com um certo prefixo:

  • Next.js: NEXT_PUBLIC_. O valor é escrito dentro do JavaScript que chega ao browser.
  • Vite: VITE_. A documentação do Vite diz explicitamente para não pôr lá chaves.
  • Expo: EXPO_PUBLIC_. O valor fica em texto simples na app compilada.

Uma chave secreta com um destes prefixos é pública, mesmo que esteja no .env. Acontece assim: a chamada à IA a partir do browser não funciona, junta-se o prefixo, agora funciona, e a chave saiu. A solução certa é passar a chamada para o servidor.

Se não queres que o Claude leia o .env

O Claude Code pode ler os ficheiros da pasta, o .env incluído. Se preferires que não, acrescenta uma regra de bloqueio em .claude/settings.json, na pasta do projeto:

O ficheiro
{
  "permissions": {
    "deny": ["Read(./.env)"]
  }
}

Põe-na depois de mudares as chaves: bloqueia também a escrita desse ficheiro. Vale para as ferramentas com que o Claude lê ficheiros e para comandos como o cat, não para um script que abre o ficheiro por conta própria: para isso é preciso a sandbox do Claude Code.

4. Se já te fugiu uma

Se encontras uma chave secreta num commit, no GitHub ou no código que vai para o browser, dá-a como queimada. Não sabes quem já a copiou. Hoje, por esta ordem:

  1. No site do serviço revoga a chave e cria uma nova. É o passo que conta: quem a copiou ainda a pode usar.
  2. Põe a nova só no .env e nas definições do alojamento.
  3. Verifica no serviço os consumos estranhos.
  4. Depois, com calma, limpa o histórico.

Se a app está online podes criar a chave nova um pouco antes de revogar a antiga, para não ficar parada. Mas a antiga revogas hoje, não amanhã. Para o último passo, pede primeiro uma explicação:

O prompt
Uma chave foi parar a um commit antigo. Explica-me como a tirar do histórico do git antes de mexer no que quer que seja.

Porquê esta ordem. Tirar uma chave do histórico quer dizer reescrever a história do repositório (o GitHub recomenda o git-filter-repo) e carregá-la com um force push, e as cópias antigas e os forks ainda a têm. Por isso o GitHub põe como primeiro passo revogar a chave, e diz que às vezes chega: uma chave revogada já não abre nada.

Os erros mais comuns

  • Apagar a chave do código e ficar por aí. Continua no histórico: revoga-a e cria uma nova.
  • Limpar o histórico antes de revogar a chave. Revoga-a logo: a limpeza vem depois.
  • Acrescentar o .env ao .gitignore quando já tinha sido carregado. Tira-o com git rm --cached .env e um commit, depois muda as chaves que lá estavam.
  • Pôr uma chave secreta numa variável NEXT_PUBLIC_, VITE_ ou EXPO_PUBLIC_. Vai parar ao browser ou à app: passa a chamada para o servidor.
  • Colar as chaves novas no chat com o Claude. Põe-nas tu no .env e diz-lhe só o nome da variável.

Checklist

  • Verificação feita aos ficheiros e ao histórico, com o Claude e com o gitleaks.
  • As chaves secretas estão só no .env e nas definições do alojamento.
  • O .env está no .gitignore e não está no repositório.
  • Há um .env.example com os nomes, sem valores.
  • Nenhuma chave secreta em variáveis NEXT_PUBLIC_, VITE_ ou EXPO_PUBLIC_.
  • Cada chave fugida foi revogada e substituída.
  • Push protection ativa no repositório do GitHub.

Perguntas frequentes

O meu repositório é privado. Tenho de fazer isto na mesma?

Sim. Se um dia o tornas público ou acrescentas alguém, o histórico vai inteiro, chaves incluídas. E as variáveis que vão parar ao browser são públicas de qualquer forma.

A chave pública do Supabase numa variável NEXT_PUBLIC_ está bem?

Sim, é feita para estar no browser. O que protege os dados são as regras na base de dados, como explico no guia PORTA. A chave secreta (secret ou service_role), essa nunca.

Já revoguei a chave. Tenho de limpar o histórico na mesma?

Nem sempre: uma chave revogada já não abre nada. Se no histórico há outra coisa sensível, como dados de pessoas, ou não tens a certeza de ter revogado tudo, limpa, a começar pelo prompt da parte 4.

← Todos os guias