Enumeração de contas: exposição que começa antes do login
Em muitos fluxos de autenticação, o primeiro contato do aplicativo com o backend acontece por uma API aberta, pensada para iniciar a…
Enumeração de contas: exposição que começa antes do login

Em muitos fluxos de autenticação, o primeiro contato do aplicativo com o backend acontece por uma API aberta, pensada para iniciar a jornada do usuário. O problema aparece quando essa etapa começa a responder de forma diferente para contas existentes e inexistentes. A partir daí, o que deveria ser apenas o começo do login pode virar um mecanismo de descoberta de identidades válidas.
Essa diferença nem precisa ser gritante. Pode estar em um status code, em um campo a mais no retorno, em uma mensagem mais específica ou até no tempo de resposta. Para quem observa o comportamento da aplicação com intenção de mapear sua superfície, isso já pode bastar.
Quando esse tipo de distinção fica exposto, a enumeração de contas deixa de ser hipótese e passa a ser possibilidade concreta. E, com uma base de contas válidas em mãos, outros abusos ganham muito mais eficiência.
Observação: esse tema costuma parecer secundário até o momento em que alguém percebe que a API está ajudando, sem querer, a separar usuários reais de entradas inválidas.
O que é enumeração de contas
Enumeração de contas acontece quando um sistema permite inferir, direta ou indiretamente, se uma identidade existe na base.
Essa identidade pode ser um e-mail, CPF, telefone, username, matrícula, número de conta ou qualquer outro identificador que participe do fluxo inicial de autenticação, recuperação ou cadastro.
O problema não está apenas em retornar algo explícito como “usuário não encontrado”. Ele também aparece quando a aplicação entrega pistas suficientes para separar contas válidas de contas inválidas.
Exemplos comuns:
- mensagens diferentes para “usuário não existe” e “senha inválida”
- códigos HTTP diferentes
- tempo de resposta inconsistente
- diferenças no payload de erro
- envio de OTP apenas para usuários existentes
- mudança de etapa do fluxo só quando a conta é válida
Como isso acontece em um app com API inicial pública e sem validação
Imagine um aplicativo mobile cujo primeiro passo de login chama uma API pública para descobrir como seguir com a autenticação.
O app envia algo assim:
{
"login": "lucas@email.com"
}
E a API responde de formas diferentes.
Para um usuário existente:
200 OK
{
"nextStep": "password",
"hasBiometrics": true,
"maskedPhone": "***1234"
}
Para um usuário inexistente:
404 Not Found
{
"message": "Usuário não encontrado"
}
Pronto. A enumeração já nasceu.
Mesmo que você esconda a mensagem, o problema continua existindo se houver qualquer diferença observável entre os dois cenários.
Por exemplo:
- um caso responde em 80 ms e o outro em 20 ms
- um fluxo retorna
200, outro404 - um payload traz metadados adicionais
- uma conta válida dispara algum efeito colateral, como envio de SMS ou geração de challenge
Com isso, alguém pode automatizar centenas ou milhares de tentativas e montar uma base de identidades reais.
Observação: o atacante nem precisa “invadir” nada nesse momento. Às vezes ele só precisa observar com cuidado aquilo que o sistema já está entregando sozinho.
Por que isso é perigoso
Muita gente olha para enumeração de contas como se ela fosse um problema menor porque, isoladamente, ela não entrega acesso.
Mas ela reduz incerteza.
E reduzir incerteza é valioso para quem quer atacar.
Quando alguém consegue separar contas válidas de inválidas, isso ajuda em várias frentes:
- força bruta mais eficiente
- credential stuffing com menor ruído
- abuso de recuperação de acesso
- phishing mais convincente
- fraude orientada a usuários reais
- coleta de inteligência sobre a base de clientes
Em outras palavras, a enumeração não costuma ser o golpe final. Ela costuma ser a etapa que prepara o terreno.
O erro clássico: confiar demais em uma API pública sem contexto do dispositivo
O cenário piora quando a API inicial é pública e aceita chamadas sem nenhum mecanismo de legitimidade do cliente.
Nesse desenho, o backend só recebe um identificador e responde. Ele não tem evidência mínima de que aquela chamada veio do aplicativo legítimo, instalado de forma válida, executando em um ambiente esperado.
Isso abre espaço para:
- scripts simples
- emuladores
- apps modificados
- chamadas diretas fora do aplicativo oficial
- automação em larga escala
A API, nesse caso, fica exposta como uma interface de consulta de existência.
E esse é justamente o ponto em que entra a discussão sobre garantir que o device é um meio legítimo para fazer a chamada.
O que muda quando o backend passa a exigir prova de legitimidade do device
A ideia aqui não é “confiar cegamente no celular”. A ideia é elevar o custo da chamada e parar de aceitar qualquer origem como se fosse equivalente.
Em vez de deixar a API pública inicial responder apenas com base no identificador informado, o servidor passa a exigir sinais adicionais de legitimidade do aplicativo e do dispositivo.
Isso pode incluir:
- prova de integridade do app
- prova de que a chamada veio do app oficial
- prova de posse de chave gerada no device
- vínculo entre requisição e dispositivo
- validações de risco antes de responder algo sensível
Com isso, a API inicial deixa de ser apenas um endpoint aberto e passa a ser uma etapa protegida por confiança progressiva.
O que resolver de forma objetiva
Se o objetivo é mitigar enumeração de contas, há algumas decisões que ajudam bastante.
1. Tornar a resposta indistinguível
Esse é o primeiro passo, e ele é obrigatório.
O sistema não deve revelar se a conta existe ou não na resposta inicial.
Isso vale para:
- mensagem
- status code
- estrutura do payload
- tempo de resposta
- efeitos colaterais visíveis
Exemplo melhor:
200 OK
{
"message": "Se os dados informados forem válidos, o próximo passo será disponibilizado."
}
Ou então um fluxo que sempre devolve a mesma estrutura e decide internamente o que fazer sem expor essa distinção ao cliente.
2. Evitar enriquecimento precoce do fluxo
Não devolva logo no começo coisas como:
- telefone mascarado
- indicação de biometria cadastrada
- método de autenticação existente
- nome parcial do usuário
- status de cadastro
Tudo isso ajuda quem está testando existência de contas.
3. Aplicar rate limit e proteção comportamental
Mesmo com resposta uniforme, a API inicial continua sendo sensível.
Então faz sentido aplicar:
- rate limiting por IP
- rate limiting por device
- rate limiting por fingerprint transacional
- proteção por janela de tempo
- detecção de padrão automatizado
4. Exigir prova de cliente legítimo antes de responder etapas sensíveis
Se a primeira chamada já é relevante para descoberta de contas, o backend pode exigir um artefato de confiança emitido ou assinado a partir do app/device legítimo antes de entregar qualquer progressão útil do fluxo.
Não é para “decorar” a chamada com header aleatório. É para mudar o modelo de confiança.
Como garantir que o device é um meio legítimo para fazer essa chamada
Não existe bala de prata. O caminho mais sólido costuma ser combinar mecanismos.
App attestation
No iOS, a Apple oferece o App Attest dentro do ecossistema DeviceCheck. A proposta é permitir que o servidor valide evidências de que a chamada está associada ao app legítimo em um dispositivo Apple.
No Android, a Play Integrity API ajuda o backend a verificar se a interação veio do app genuíno, instalado pelo Google Play, rodando em um dispositivo Android íntegro e certificado.
Esses mecanismos não “resolvem tudo”, mas mudam bastante o jogo. Eles ajudam a filtrar chamadas de apps adulterados, ambientes suspeitos e clientes não oficiais.
Prova de posse de chave no device
Outro caminho forte é fazer o app gerar ou usar uma chave atrelada ao dispositivo e usar essa chave para assinar desafios ou requisições.
Aqui a ideia não é só perguntar “quem está chamando?”, mas também “você consegue provar posse da chave que espero desse cliente?”.
Isso ajuda a sair de um modelo baseado apenas em identificador enviado para um modelo com evidência criptográfica de origem.
Challenge do servidor
Em vez de aceitar chamadas diretas e repetíveis, o backend pode emitir um challenge e exigir que o app o devolva processado da forma esperada.
Esse challenge deve ser:
- curto
- de uso único
- vinculado à sessão ou tentativa
- validado no backend
- descartado após uso
Isso reduz replay e aumenta o custo de automação.
Binding transacional
Outra camada útil é vincular a prova técnica ao contexto da transação.
Por exemplo:
- device attestation
- nonce
- request signing
- janela curta de validade
- correlação com telemetria de risco
O ganho aqui é que a chamada deixa de ser apenas “um POST com login” e passa a exigir coerência entre cliente, artefato, tempo e contexto.
O que esses mecanismos não resolvem sozinhos
App attestation não substitui:
- resposta uniforme
- rate limit
- observabilidade
- proteção contra enumeração por tempo
- análise de abuso
- desenho correto do fluxo
Se a API continuar respondendo de forma diferente para conta existente e inexistente, você ainda terá problema. A diferença é que talvez ele fique restrito a um conjunto menor de clientes capazes de passar pela primeira barreira.
Ou seja: attestation ajuda muito, mas não corrige sozinho um fluxo mal desenhado.
Observação: esse é um erro comum em segurança mobile. Às vezes se coloca uma tecnologia forte na borda, mas o comportamento funcional continua entregando informação demais.
Ferramentas e possibilidades que ajudam nisso
No iOS
- App Attest, para validar evidências de legitimidade do app junto ao backend
- DeviceCheck, como parte do ecossistema de verificação da Apple
- armazenamento seguro de chaves no ecossistema Apple, combinado com assinatura de challenge
- detecção de jailbreak e sinais de ambiente comprometido, como camada complementar
No Android
- Play Integrity API, para obter verdicts sobre legitimidade do app e do ambiente
- Android Keystore e estratégias de prova de posse de chave
- detecção de root, tampering e execução suspeita como sinal complementar
- validação server-side forte dos tokens ou verdicts recebidos
No backend
- resposta uniforme
- rate limiting
- anti-automation
- challenge-response
- request signing
- telemetria de risco
- correlação de eventos
- observabilidade para padrões de enumeração
- bloqueio progressivo e step-up
Como referência de boas práticas
O OWASP MASVS e o material do OWASP MAS tratam segurança mobile como disciplina estruturada, incluindo verificação de controles e fraquezas relacionadas à ausência de attestation no app.
Fechamento
Enumeração de contas não costuma nascer de algo extraordinário. Muitas vezes, ela aparece quando o próprio fluxo inicial entrega pistas demais para quem está olhando com atenção.
O problema já não é só a existência de uma API pública, mas a forma como ela responde e o quanto ela confia em qualquer cliente que consiga chegar até ela.
No fim, proteger esse cenário passa por duas decisões simples de entender, mas importantes de sustentar: não revelar se a conta existe e não tratar toda chamada como igualmente legítima.
Agradeço a todos que chegaram até o final. Se este artigo ajudou, mesmo que um pouco, já valeu a pena escrevê-lo.
Até a próxima, Lucas Carvalho
메타데이터
- post_id
- af849d05bc56
- slug
- enumeração-de-contas-exposição-que-começa-antes-do-login-af849d05bc56
- url
- https://medium.com/@lucascarvalhodeveloper/enumera%C3%A7%C3%A3o-de-contas-exposi%C3%A7%C3%A3o-que-come%C3%A7a-antes-do-login-af849d05bc56
- canonical_url
- https://medium.com/@lucascarvalhodeveloper/enumera%C3%A7%C3%A3o-de-contas-exposi%C3%A7%C3%A3o-que-come%C3%A7a-antes-do-login-af849d05bc56
- author_url
- https://medium.com/@lucascarvalhodeveloper
- status
- ok
- fetched_at
- 2026-06-21 15:33:18