Chaves de API explicadas: tamanho, formato, armazenamento e rotação
Uma chave de API é uma sequência longa e aleatória que um programa envia em cada requisição para mostrar qual aplicação está chamando. Ao contrário de uma senha, ninguém precisa decorá-la, então ela pode ser tão longa e aleatória quanto for preciso. Ao contrário de um token de login, ela costuma valer até alguém revogá-la. A documentação do Google resume o risco: chaves de API são credenciais ao portador, então quem tem uma pode usá-la.
Esta quarta parte da série sobre segurança percorre a vida inteira de uma chave: quantos bits aleatórios ela precisa ter, em que formato escrevê-la, por que existem prefixos como sk_live_, como enviá-la, o que o servidor deve guardar e como fazer a rotação e a revogação.
Chave de API, senha ou token de acesso?
Os três provam algo para um servidor, e por isso são confundidos com frequência. A diferença está em quem os cria, quanto tempo duram e o que o servidor guarda:
| Credencial | Criada por | Validade | O servidor guarda |
|---|---|---|---|
| Senha | uma pessoa | até a pessoa trocá-la | um hash lento (Argon2id, scrypt, bcrypt) |
| Chave de API | um gerador aleatório | até ser trocada ou revogada | um hash rápido, como SHA-256 |
| Token de acesso (OAuth, JWT) | o servidor de login, depois de um login | de minutos a horas | uma assinatura para verificar, ou um registro do token |
Uma chave de API normalmente identifica uma aplicação ou uma integração, não uma pessoa. Quando uma chave faria o papel de uma pessoa fazendo login, um token de acesso obtido num fluxo de login de verdade costuma ser a ferramenta melhor, como explica a parte anterior, sobre JSON Web Tokens.
Qual deve ser o tamanho de uma chave
O que protege uma chave é o número de bits aleatórios que ela tem, não o tamanho em caracteres. Cada bit dobra o número de chaves possíveis: 128 bits aleatórios permitem cerca de 3,4 × 10³⁸ chaves, então testar nem que seja um milionésimo delas a um bilhão de tentativas por segundo levaria cerca de 10¹⁶ anos, quase um milhão de vezes a idade do universo. Por isso 128 bits é um mínimo sólido, e 256 bits custam só alguns caracteres a mais.
Os bits precisam vir de um gerador aleatório criptográfico. No navegador, é o crypto.getRandomValues(); a MDN avisa que o Math.random() não fornece números criptograficamente seguros e não deve ser usado para nada relacionado a segurança. As linguagens de servidor têm seus equivalentes, como o módulo secrets do Python ou o crypto.randomBytes() do Node.js.
O GitHub aumentou seus tokens OAuth de 160 para 178 bits de entropia quando mudou o formato deles em 2021. Um caso precisa de ainda mais: um segredo que assina JSON Web Tokens com HMAC. O RFC 7518 exige uma chave pelo menos do tamanho da saída do hash: 256 bits para HS256, 384 para HS384 e 512 para HS512.
Formatos: base62, hexadecimal ou base64url
Os bits aleatórios precisam ser escritos como texto. O alfabeto decide quantos caracteres são necessários e onde a chave pode ser colada sem problema:
| Formato | Caracteres | Bits por caractere | Tamanho para 256 bits |
|---|---|---|---|
base62 | a–z, A–Z, 0–9 | 5,95 | 43 |
hex | 0–9, a–f | 4 | 64 |
base64url | a–z, A–Z, 0–9, - e _ | 6 | 43 |
O base62 virou comum para chaves porque só tem letras e números: nada que uma URL, um terminal ou um arquivo de configuração tratem de forma especial, e um clique duplo seleciona a chave inteira. O hexadecimal é mais longo, mas funciona onde só 0–9 e a–f são aceitos. O base64url, do RFC 4648, é o mais curto, mas o - dele pode interromper a seleção com clique duplo. O Base64 padrão é uma escolha ruim, porque o + e a / precisam ser codificados em URLs.
Escrever base62 corretamente exige cuidado: um byte aleatório tem 256 valores, e 256 não é múltiplo de 62, então um simples byte % 62 deixa os oito primeiros caracteres um pouco mais prováveis. Um bom gerador descarta os bytes a partir de 248, como faz o gerador do nTools.
Prefixos e varredura de segredos
Muitos provedores começam suas chaves com um prefixo fixo e legível. As chaves secretas da Stripe começam com sk_live_ ou sk_test_, as chaves publicáveis com pk_ e as restritas com rk_. Desde 2021, os tokens do GitHub começam com ghp_ nos tokens de acesso pessoal, gho_ nos tokens OAuth e ghs_ nos de servidor para servidor.
sk_live_…Chave secreta da Stripe, modo de produção: pagamentos de verdade.pk_test_…Chave publicável da Stripe, sandbox: pode ir numa página web.ghp_…Token de acesso pessoal do GitHub.
Um prefixo não é secreto e não deixa a chave mais forte, mas cumpre três funções úteis. Dá para ver de relance para que serve uma chave e se ela é de teste. O GitHub escolheu o sublinhado porque ele não é um caractere do Base64, então sequências aleatórias como hashes não podem parecer um token por acaso, e porque um clique duplo seleciona o token inteiro. Acima de tudo, um prefixo permite que scanners encontrem chaves vazadas: a varredura de segredos do GitHub percorre todo o histórico do Git de todos os branches e, quando encontra o segredo de um provedor parceiro, avisa esse provedor, que pode revogar a chave.
O GitHub também termina seus tokens com um checksum CRC32 de 32 bits escrito em seis caracteres base62. Ele não acrescenta segurança, mas permite que um scanner descarte sequências aleatórias offline, sem perguntar ao servidor se o token existe.
Envie num cabeçalho, nunca na URL
O RFC 6750, que define os tokens ao portador do OAuth 2.0, diz que os clientes devem enviá-los no cabeçalho Authorization e não colocá-los nas URLs das páginas, porque os endereços acabam no histórico do navegador e nos logs dos servidores. O Google dá o mesmo conselho para as próprias chaves de API e oferece um cabeçalho para elas. O mesmo RFC exige TLS: uma chave enviada por http simples pode ser lida por qualquer um no caminho.
Authorization: Bearer sk_live_…Recomendado: a chave viaja num cabeçalho, por https.https://api.example.com/v1/orders?api_key=sk_live_…Evite: a chave acaba nos logs e no histórico do navegador.
O que o servidor deve guardar
O servidor não precisa guardar a chave em si, só uma forma de reconhecê-la. Guarde um hash da chave, como o SHA-256 dela; quando chegar uma requisição, calcule o hash da chave recebida e procure esse hash. Se o banco de dados vazar, os hashes não servem para chamar a API, e não dá para recuperar as chaves a partir deles.
Senhas precisam de um hash lento porque, como explica o Password Storage Cheat Sheet da OWASP, um hash rápido como o SHA-256 permite que atacantes testem uma quantidade enorme de tentativas em pouco tempo. Esse raciocínio depende de as senhas poderem ser adivinhadas. Uma chave com 256 bits aleatórios não pode, então um único hash rápido basta, e cada requisição continua rápida.
Como só o hash é guardado, a chave completa só pode ser mostrada uma vez, na criação. A Stripe funciona assim com as chaves secretas de produção que você mesmo cria: o painel mostra a chave uma única vez e não consegue revelá-la de novo. Guarde em claro o prefixo e os últimos caracteres se as pessoas precisarem distinguir suas chaves.
Manter as chaves fora do código
Chaves vazadas aparecem principalmente onde os desenvolvedores as colocaram por comodidade. A Stripe avisa que pessoas mal-intencionadas varrem o tempo todo os repositórios públicos em busca de chaves de API, e que mesmo repositórios privados podem ficar expostos. Os conselhos dela, repetidos pelo Google e pela OWASP:
- Nunca escreva uma chave no código-fonte, num arquivo de configuração sob controle de versão ou num app que as pessoas baixam: apps podem ser descompactados.
- Carregue as chaves em tempo de execução de um gerenciador de segredos, como AWS Secrets Manager, Google Cloud Secret Manager, Azure Key Vault ou HashiCorp Vault. Variáveis de ambiente são um plano B: a OWASP observa que qualquer processo pode lê-las e que elas podem ir parar nos logs.
- Nunca grave uma chave em log, e nunca mostre a configuração ou as variáveis de ambiente numa página de erro.
- Dê a cada aplicação, e a cada pessoa, uma chave própria, só com as permissões necessárias. As chaves restritas da Stripe e as restrições de chave do Google limitam o que uma chave roubada pode fazer.
- Coloque um scanner de segredos num hook de pre-commit, para que uma chave seja recusada antes de chegar ao repositório.
Rotação e revogação
Toda chave deve poder ser trocada em pouco tempo. Fazer a rotação é criar uma chave nova, passar todas as aplicações para ela e depois apagar a antiga. Feita periodicamente, ela limita por quanto tempo uma chave roubada continua funcionando e, como lembra a Stripe, prova que você sabe onde cada chave é usada. O painel da Stripe mantém a chave antiga e a nova funcionando juntas por até sete dias para a troca ser tranquila.
Quando uma chave fica exposta — enviada para um repositório, colada num chat, impressa num log —, revogue-a na hora, mesmo sem ter certeza de que alguém a viu. Apagar o commit não basta: a chave pode já ter sido copiada e continua no histórico do Git e em cada clone. Quando o sistema permitir, dê também uma data de validade às chaves, para que uma chave esquecida pare de funcionar sozinha.
Gerar uma chave
O gerador de chaves de API do nTools cria chaves em base62, hexadecimal ou base64url, de 128 a 512 bits, com prefixo opcional e, se você quiser, o hash SHA-256 para guardar no servidor. Ele usa o crypto.getRandomValues() e funciona inteiramente no seu navegador: as chaves não são enviadas para lugar nenhum.
Perguntas frequentes
Posso usar um UUID como chave de API?
Um UUID versão 4 tem só 122 bits aleatórios e um formato fixo e reconhecível, e foi criado como identificador, não como segredo. É melhor gerar uma chave própria com 128 bits ou mais.
Uma chave gerada no navegador é segura?
Sim, se vier do crypto.getRandomValues(), o gerador criptográfico que o navegador usa na própria segurança, e se a página não a enviar para lugar nenhum. O gerador do nTools funciona assim: nenhuma requisição sai da página quando você clica em “Gerar”.
Chaves de API devem expirar?
Quando o sistema permite, sim: uma data de validade limita o estrago de uma chave esquecida ou vazada sem ninguém perceber. Chaves de longa duração são comuns, o que torna a rotação e a revogação rápida ainda mais importantes.
Enviei uma chave para o Git. E agora?
Primeiro revogue ou troque a chave, depois limpe o repositório. Reescrever o histórico depois não deixa a chave segura de novo, porque ela pode já ter sido copiada.
É melhor criptografar a chave em vez de guardar o hash?
Só se o próprio servidor precisar usar a chave depois, por exemplo para chamar outro serviço com ela. Uma chave que só precisa ser verificada deve ser guardada como hash: assim não há nada para descriptografar se o banco vazar.
Anterior da série ← JSON Web Tokens explicados: claims, assinaturas e validação segura
Referências
- GitHub — Behind GitHub’s new authentication token formats (April 2021)
- GitHub Docs — About secret scanning
- GitHub Docs — About secret scanning for partners
- Stripe — API keys
- Stripe — Best practices for managing secret API keys
- Google Cloud — Best practices for managing API keys
- RFC 6750 — The OAuth 2.0 Authorization Framework: Bearer Token Usage (October 2012)
- RFC 7518 — JSON Web Algorithms (JWA) (May 2015)
- RFC 4648 — The Base16, Base32, and Base64 Data Encodings (October 2006)
- OWASP — Secrets Management Cheat Sheet
- OWASP — Password Storage Cheat Sheet
- MDN — Crypto: getRandomValues()
- MDN — Math.random()
Guias relacionados
- Endereços IP explicados: IPv4, IPv6 e as faixas reservadas
- Sub-redes e CIDR explicados: prefixos, máscaras e hosts utilizáveis
- Registros DNS explicados: A, AAAA, CNAME, MX, TXT e NS
- Um site está fora do ar ou é só com você? Como verificar, passo a passo
- Códigos de status HTTP e erros da Cloudflare: o que significam 403, 404, 429, 500, 503 e 521
- Timestamps Unix e fusos horários explicados
- Contagem de datas: dias entre datas, anos bissextos e semanas ISO
- Formatos de imagem explicados: JPEG, PNG, WebP, AVIF e HEIC
- O tamanho de uma imagem explicado: pixels, DPI, peso e qualidade
- Fotos de celular explicadas: HEIC, metadados EXIF e sua privacidade
- Força de senhas explicada: comprimento, entropia e frases-senha
- Funções de hash explicadas: SHA-256, checksums e hash de senhas
- JSON Web Tokens explicados: claims, assinaturas e validação segura
- UUIDs explicados: v4, v7 e como escolher a versão certa
- QR codes explicados: capacidade, correção de erros e tamanho de impressão
- Porcentagens e IVA explicados: somar, tirar e acumular
- Erros comuns em JSON e como corrigi-los
- Arquivos CSV explicados: separadores, aspas, codificação e Excel
- Codificações de texto explicadas: UTF-8, Base64 e codificação de URL
- Edição de PDFs no navegador: o que se mantém ao juntar, dividir e converter