Autenticação

TL;DR

Autenticação é provar quem você é — distinta de identificação (alegar quem você é) e de autorização (o que você pode fazer). Os três fatores clássicos — algo que você sabe, tem ou é — formam a base do MFA. Senhas sozinhas são fracas por design: vazam, são reutilizadas e atraem phishing. FIDO2/WebAuthn resolve o problema raiz: o segredo nunca sai do dispositivo, a credencial é vinculada à origem e não há servidor guardando segredo para vazar.


Deep-dive de protocolo e implementação

Esta nota é o conceito neutro. Para o mergulho em protocolos e stacks — sessões e cookies, JWT, passkeys/WebAuthn, OAuth 2.1, OpenID Connect, MFA na prática e o IdP Keycloak — veja a trilha Auth e Identidade (fundamentos em Fundamentos de identidade).

Identificação × autenticação × autorização

A distinção é cobrada em toda entrevista de segurança. São três etapas sequenciais, frequentemente confundidas:

EtapaPerguntaExemploPode ser falsificada?
Identificação”Quem afirma ser você?”Digitar o usernameSim — qualquer um digita “admin”
Autenticação (authN)“Você consegue provar essa identidade?”Fornecer senha + OTPDepende do mecanismo
Autorização (authZ)“O que essa identidade pode fazer?”Verificar permissões no RBACSó executa depois de authN

Identificação é apenas uma afirmação — qualquer um pode digitar admin. Autenticação exige prova verificável. Autorização é consequência: só faz sentido depois de autenticar com sucesso.

A confusão entre as três etapas produz bugs clássicos de segurança:

  • Checar if user.username == "admin" sem verificar a autenticação primeiro → qualquer um que alegue ser “admin” é tratado como tal.
  • Expor endpoint de autorização sem autenticação → o sistema aceita qualquer identidade alegada.
  • Confundir sessão válida com permissão → if session.valid: do_anything() ignora completamente o controle de acesso.
flowchart TD
    A["Usuario informa username"] --> B{"Identidade existe?"}
    B -->|"Nao"| C["Rejeitar — identidade desconhecida"]
    B -->|"Sim"| D["Solicitar prova de identidade"]
    D --> E{"Prova valida?"}
    E -->|"Nao"| F["Falha de authN — nao autenticado"]
    E -->|"Sim"| G["Autenticado — emitir token de sessao"]
    G --> H["Receber requisicao com token"]
    H --> I["Verificar permissoes (authZ)"]
    I -->|"Sem permissao"| J["403 Forbidden"]
    I -->|"Com permissao"| K["Executar acao — acesso concedido"]

Leitura do diagrama

As três etapas são estritamente sequenciais: identificação → autenticação → autorização. Um sistema que pula a autenticação aceita qualquer identidade alegada como verdade, abrindo brechas de identity spoofing imediato. A emissão do token de sessão marca a fronteira entre authN e authZ.


Os três fatores de autenticação

O modelo canônico agrupa evidências de identidade em três categorias. A força do MFA depende de combinar categorias diferentes — não de empilhar fatores da mesma categoria.

graph LR
    MFA["Multi-Factor Authentication"] --> SABE["Algo que voce SABE"]
    MFA --> TEM["Algo que voce TEM"]
    MFA --> E["Algo que voce E"]

    SABE --> S1["Senha / passphrase"]
    SABE --> S2["PIN"]
    SABE --> S3["Resposta a pergunta secreta"]

    TEM --> T1["Smartphone com TOTP ou push"]
    TEM --> T2["Hardware token YubiKey / FIDO2"]
    TEM --> T3["Smartcard com certificado"]
    TEM --> T4["Magic link enviado ao e-mail"]
    TEM --> T5["Chip de SIM via SMS"]

    E --> B1["Impressao digital"]
    E --> B2["Reconhecimento facial"]
    E --> B3["Reconhecimento de voz / retina"]

Leitura do diagrama

MFA real exige fatores de categorias diferentes. Dois fatores do tipo “algo que você sabe” — ex.: senha + PIN — não constituem MFA porque um adversário que comprometeu o canal de um provavelmente comprometeu o outro. O SMS está no quadrante “algo que você tem”, mas é a opção mais fraca daquela categoria.

Por que a categoria importa: imagine um adversário que comprometeu o servidor de e-mail da organização. Ele obtém tanto a senha (armazenada no mesmo domínio) quanto o magic link enviado ao e-mail corporativo. Dois fatores, mesma superfície de ataque — não é MFA real.

SMS como 2º fator é categoricamente fraco

SMS é “algo que você tem” (o SIM), mas vulnerável a SIM swap (engenharia social na operadora trocando o número para um SIM controlado pelo adversário) e ao protocolo SS7 (ataques de interceptação em redes de telecomunicação legadas, viáveis para atores com acesso a infraestrutura de telecomunicação). O NIST SP 800-63B deprecou o SMS OOB como autenticador recomendado desde 2017. Use TOTP ou passkeys.

Autenticação adaptativa (risk-based)

Sistemas modernos combinam os três fatores com sinais contextuais para calibrar a exigência de prova:

  • IP/geolocalização incomum → acionar 2º fator mesmo que o 1º tenha passado
  • Dispositivo desconhecido → exigir verificação adicional
  • Horário atípico → aumentar o nível de assurance exigido
  • Velocidade impossível → login de São Paulo e de Tóquio em 5 minutos → forçar re-authN

Isso é chamado de step-up authentication: o sistema escala a exigência de prova de acordo com o risco percebido da ação ou do contexto.


Senhas — por que são estruturalmente ruins

Senhas são o mecanismo mais difundido e o mais problemático. Não é questão de implementação ruim — é questão de modelo fundamental:

  • Reuso entre sites: usuários reutilizam senhas porque lembrar dezenas é humanamente inviável. Uma única violação num site qualquer expõe contas em todos os outros onde a mesma senha foi usada (credential stuffing).
  • Entropia efetiva baixa: humanos escolhem padrões predizíveis — nomes de pets, datas, palavras com substituição de letras (3 por e, @ por a). O espaço real de senhas escolhidas por humanos é ordens de magnitude menor que o teórico.
  • Phishing: o usuário é induzido a digitar a senha num site falso. A senha viaja para o adversário sem nenhuma verificação do lado do servidor.
  • Vazamentos em lote: bancos de dados de senhas vazam constantemente. Se armazenadas em texto claro ou com hashing fraco (MD5, SHA1 sem salt), ficam expostas em minutos com tabelas arco-íris ou GPUs modernas.
  • Compartilhamento não autorizado: senhas são secretos que podem ser ditos — anotados em papel, compartilhados por mensagem, lembrados em voz alta.

Armazenamento correto de senhas

Nunca armazene senhas em texto claro nem com hash criptográfico genérico. Hashes rápidos (SHA-256, MD5) são projetados para velocidade — um adversário com GPU consegue bilhões de tentativas por segundo.

O mecanismo correto é um hash de senha com salt e custo ajustável — consulte 06 - Hashing criptográfico para a análise completa. O resumo:

  • bcrypt (1999, ainda seguro, fator de custo padrão ≥ 12), scrypt (resistente a hardware customizado, usa memória), Argon2id (vencedor do Password Hashing Competition 2015, recomendação atual do NIST, combina resistência a GPU e a ataques side-channel).
  • O salt é gerado aleatoriamente (≥ 128 bits, CSPRNG) e único por senha — elimina rainbow tables e força cada hash a ser atacado individualmente.
  • O custo (work factor, iterações, memória) aumenta o tempo de cálculo para dificultar brute force offline sem impactar o login normal perceptivelmente (meta: ~300ms no servidor).
  • O hash resultante inclui o salt e o parâmetro de custo — basta armazenar uma string opaca, como $argon2id$v=19$m=65536,t=3,p=4$....

Erros fatais comuns de armazenamento

  • Armazenar em texto claro (violação → exposição imediata total)
  • Usar MD5 ou SHA1 sem salt (quebráveis em segundos com hardware comum)
  • Usar SHA-256/SHA-512 sem salt e sem custo (rápido demais — bilhões de tentativas/segundo)
  • Salt fixo ou derivado do username (elimina a proteção contra rainbow tables)
  • Criptografar em vez de hashear (criptografia é reversível — basta vazar a chave)

O que o NIST SP 800-63B diz — contra-intuitivo mas correto

O NIST revisou radicalmente as diretrizes em 2017 e confirmou na revisão de 2024. As recomendações derrubam décadas de “boas práticas” que na verdade pioravam a segurança:

Prática antigaPosição NIST modernaPor quê
Forçar troca periódica (90 dias)NÃOGera senhas previsíveis — usuários incrementam: Senha1!Senha2!
Exigir mistura de maiúsculas + números + especiaisNÃOReduz o espaço real de escolha; incentiva substituições óbvias (@ por a)
Limite de comprimento (ex.: máx. 16 chars)NÃODeve aceitar pelo menos 64 caracteres; comprimento é o principal driver de entropia
Verificação contra listas de senhas vazadasSIMChecar contra HaveIBeenPwned ou listas equivalentes no registro e na troca
Suporte a gerenciadores de senhaSIMPermitir colar a senha, não bloquear paste; gerenciadores geram entropia alta
Perguntas de segurança (“nome do pet?“)NÃOEntropia mínima, informação pública ou obtida por engenharia social

O pior design de senha possível

Forçar troca a cada 90 dias + exigir !@#$ + limitar a 16 chars + bloquear colar = exatamente o oposto do objetivo. Usuários criam senhas mais curtas, mais previsíveis e com padrões mais óbvios. O único requisito que importa é: comprimento mínimo ≥ 8 (≥ 15 recomendado), máximo ≥ 64, e checagem contra lista de senhas comprometidas.


Algo que você tem — OTP e derivados

One-Time Passwords eliminam o problema de replay: a senha válida expira em segundos ou é usada uma única vez, tornando interceptação seguida de reuso ineficaz.

TOTP — RFC 6238

TOTP (Time-based One-Time Password) é o algoritmo por trás do Google Authenticator, Authy, Microsoft Authenticator e similares. Baseia-se no HOTP (RFC 4226), substituindo o contador por uma função do tempo:

TOTP(K, T) = HOTP(K, T)
T = floor((UnixTime() − T₀) / X)   // X = 30 segundos, T₀ = Unix epoch
HOTP(K, C) = Truncate(HMAC-SHA1(K, C))
  • K = segredo compartilhado de 20 bytes (provisionado via QR code otpauth://)
  • T = número da janela de 30 segundos desde o Unix epoch
  • Truncate = extrai 6 dígitos do HMAC de 160 bits (Dynamic Truncation do RFC)
  • O servidor e o cliente derivam o mesmo OTP independentemente e sem comunicação em tempo real
  • Tolerância de ±1 janela (±30s) acomoda dessincronismo de relógio entre cliente e servidor
sequenceDiagram
    participant U as Usuario (Authenticator App)
    participant S as Servidor

    Note over U,S: Provisionamento (uma unica vez)
    S->>S: Gerar segredo K (20 bytes aleatorios)
    S-->>U: Segredo K via QR code (otpauth://)
    U->>U: Armazenar K no app

    Note over U,S: Login (cada vez — sem comunicacao do segredo)
    U->>U: T = floor(Unix_time / 30)
    U->>U: OTP = HMAC-SHA1(K, T) truncado em 6 digitos
    U->>S: username + senha + OTP

    S->>S: Calcular OTP esperado com mesmo K e T atual
    S->>S: Comparar (com tolerancia de +-1 janela)
    alt OTP valido e nao reutilizado
        S-->>U: 200 OK — autenticado
    else OTP invalido ou expirado
        S-->>U: 401 Unauthorized
    end

Leitura do diagrama

O segredo K é provisionado uma única vez e nunca mais transmitido. Nas autenticações subsequentes, servidor e cliente computam o mesmo valor TOTP de forma independente a partir do tempo atual. O OTP expira em ≤ 30 segundos, tornando replay inviável. O servidor deve registrar OTPs usados para evitar reuso dentro da mesma janela.

HOTP (RFC 4226) usa contador em vez de tempo — exige sincronização do contador entre cliente e servidor, que deriva ao longo do tempo. TOTP elimina esse problema usando o relógio como contador implícito e é preferido na prática.

Limitações do TOTP:

  • O segredo K deve ser armazenado no servidor (se o servidor vazar, os segredos vazam)
  • Ainda vulnerável a phishing em tempo real — adversário cria proxy transparente, captura o OTP e o usa imediatamente (man-in-the-browser)
  • Dependente de relógio sincronizado (NTP) — deriva > 1 janela produz falhas de autenticação

Magic link: e-mail com token de uso único (UUID ou token de 256 bits). O usuário clica no link sem digitar senha. Segurança depende completamente da segurança da caixa de e-mail — se o e-mail não tem MFA, o magic link é um fator único com a segurança do e-mail como superfície.

Push notification: o app móvel recebe a notificação e o usuário aprova com um toque. Confortável, mas vulnerável a MFA fatigue: adversário dispara notificações repetidamente (ataque automatizado) até o usuário, frustrado, aceitar sem perceber que não foi ele que iniciou o login. Mitigação: mostrar contexto da requisição no push (IP, localização, aplicativo) e exigir aprovação explícita com número de correspondência.

Hardware tokens e smartcards

YubiKey e equivalentes armazenam credenciais em hardware com proteção física contra extração. Suportam múltiplos protocolos: OTP, FIDO2/WebAuthn, PIV (smartcard), OpenPGP. Smartcards com certificado X.509 são padrão em ambientes governamentais (CAC nos EUA) — combinam “algo que você tem” (o card) com “algo que você sabe” (o PIN que desbloqueia o certificado privado).


FIDO2 / WebAuthn / Passkeys — o estado da arte

FIDO2 é o padrão que resolve os problemas estruturais das senhas e do TOTP. É composto por dois componentes:

  • WebAuthn (W3C Recommendation): API do navegador e do SO para criar e usar credenciais de chave pública. Suportada nativamente por Chrome, Firefox, Safari, Edge desde 2019.
  • CTAP2 (Client-to-Authenticator Protocol 2): protocolo entre o navegador/plataforma e o autenticador externo (YubiKey, passkey no smartphone via Bluetooth).

Passkeys é o nome de marketing para credenciais FIDO2 sincronizadas entre dispositivos via nuvem (iCloud Keychain, Google Password Manager, 1Password). A spec é idêntica — a diferença é que o par de chaves é copiado entre dispositivos do mesmo usuário, aliviando o problema de “e se perder o dispositivo?“.

O modelo de chave pública — sem segredo no servidor

O device (smartphone, computador, chave física) gera um par de chaves por credencial por origem:

  • Chave privada: fica no dispositivo, protegida pelo enclave seguro (Secure Enclave no iOS, TEE/StrongBox no Android, TPM em PCs com Windows Hello). Nunca sai do hardware — nem para backup em texto claro.
  • Chave pública: enviada ao servidor durante o registro e armazenada lá.
sequenceDiagram
    participant B as Navegador / Plataforma
    participant A as Autenticador (Secure Enclave / TEE)
    participant S as Servidor (Relying Party)

    Note over B,S: REGISTRO (uma unica vez por dispositivo)
    B->>S: POST /register/begin
    S-->>B: {challenge, rpId, userId, ...}
    B->>A: navigator.credentials.create({challenge, rpId})
    A->>A: Verificar consentimento do usuario (biometria ou PIN local)
    A->>A: Gerar par (privKey, pubKey) vinculado ao rpId
    A->>A: Assinar challenge com privKey
    A-->>B: {credentialId, pubKey, attestation, assinatura}
    B->>S: POST /register/complete com pubKey + assinatura
    S->>S: Verificar assinatura com pubKey
    S->>S: Armazenar {userId, credentialId, pubKey}

    Note over B,S: LOGIN (cada vez — zero segredo transmitido)
    B->>S: POST /login/begin com username ou discoverable
    S-->>B: {challenge, rpId, allowCredentials}
    B->>A: navigator.credentials.get({challenge, rpId})
    A->>A: Verificar que rpId == origem atual (anti-phishing)
    A->>A: Verificar consentimento do usuario
    A->>A: Assinar {challenge + authenticatorData} com privKey
    A-->>B: {credentialId, assinatura, authenticatorData}
    B->>S: POST /login/complete com assinatura
    S->>S: Buscar pubKey pelo credentialId
    S->>S: Verificar assinatura com pubKey
    S-->>B: 200 OK + session token

Leitura do diagrama

No registro, a chave pública vai para o servidor; a privada permanece no enclave seguro do dispositivo. No login, o servidor envia um desafio aleatório (challenge); o autenticador assina com a privada após verificar biometria/PIN local. O servidor verifica com a pública. Nenhum segredo é transmitido em nenhum momento — nem a senha, nem a chave privada, nem o OTP.

Por que passkeys são resistentes a phishing

A propriedade central e mais importante: a credencial é vinculada à origem (rpId = o domínio exato do servidor registrado, verificado pelo autenticador).

Cenário de phishing com senha + TOTP:

  1. Adversário cria banco-falso.com idêntico visualmente ao banco.com
  2. Usuário digita usuário, senha e TOTP no site falso
  3. O proxy adversário usa tudo imediatamente no site real
  4. Conta comprometida em segundos

Cenário de phishing com passkey:

  1. Adversário cria banco-falso.com
  2. Navegador solicita ao autenticador uma assinatura para rpId = banco-falso.com
  3. O autenticador não encontra credencial para esse rpId
  4. Autenticação falha — não há como o usuário “errar” e fornecer a credencial

O que passkeys eliminam simultaneamente

  • Phishing: credencial não funciona em origem diferente da registrada
  • Credential stuffing: não existe senha reutilizável para vazar de outro serviço
  • Vazamento de banco de dados: servidor armazena apenas chave pública — inútil sem a privada
  • Brute force: não há segredo de baixa entropia para adivinhar
  • Keyloggers: nada é digitado — nenhum segredo sai do enclave seguro

Attestation — verificar o autenticador

Durante o registro, o autenticador pode fornecer um attestation statement — uma assinatura do fabricante que prova a classe de autenticador usado (modelo de YubiKey, versão do iOS, etc.). Útil em cenários corporativos onde a política exige hardware certificado FIDO. Em passkeys consumer, attestation frequentemente é “none” por privacidade.


Ataques a autenticação e defesas

flowchart TD
    CR["Credential Stuffing\n(listas de vazados)"] --> D1["MFA + checagem Pwned Passwords"]
    PH["Phishing de senha\n(site falso)"] --> D2["Passkeys / FIDO2 — origin-bound"]
    PS["Password Spraying\n(poucas senhas, muitos users)"] --> D3["Rate limiting por IP + lockout progressivo + alertas"]
    BF["Brute Force\n(muitas senhas, 1 user)"] --> D4["Lockout + CAPTCHA + bcrypt/Argon2"]
    SW["SIM Swap\n(engenharia social na operadora)"] --> D5["Substituir SMS por TOTP ou passkey"]
    MM["MITM / Replay\n(intercept e reuso)"] --> D6["TLS + nonce + tokens com expiracao curta"]
    PH2["Pass-the-Hash\n(roubo de hash NTLM)"] --> D7["Credential Guard + desabilitar NTLMv1"]
    MF["MFA Fatigue\n(flood de push)"] --> D8["Push com numero de correspondencia + limite de tentativas"]

Leitura do diagrama

Cada vetor de ataque exige uma defesa específica. Passkeys eliminam phishing e credential stuffing simultaneamente. Rate limiting e lockout atrasam ataques de força mas não eliminam — MFA é a defesa real contra senhas fracas/vazadas. MFA fatigue é específico de push notifications e exige mitigação no design do prompt.

Taxonomia detalhada dos ataques

Credential stuffing: adversário obtém pares username:senha de vazamentos públicos (ex.: dumps no Have I Been Pwned) e os testa em lote em outros serviços via automação. Funciona porque usuários reutilizam senhas. Defesas: MFA, detecção de anomalias (volume de falhas, diversidade de IPs), checagem de senha contra listas de vazados no momento do login.

Password spraying: em vez de atacar um usuário com muitas senhas (o que dispara lockout), ataca muitos usuários com poucas senhas muito comuns (Senha123, Primavera2024, Welcome1). Evita lockout por usuário individual. Defesa: rate limiting por IP de origem + lockout suave (delay crescente, não bloqueio total) + alertas por volume anômalo de falhas.

Brute force: exaustão sistemática do espaço de senhas. Eficaz online apenas contra sistemas sem rate limiting. Muito mais eficaz offline (quando o hash vaza) — por isso Argon2 importa. Uma GPU moderna consegue ~10⁹ tentativas/s contra MD5; contra Argon2id com parâmetros adequados, cai para ~10² tentativas/s.

MITM e replay: adversário intercepta o tráfego (sem TLS ou com certificado inválido aceito pelo usuário) e reutiliza tokens capturados. TLS mitiga MITM; tokens com expiração curta, nonce e binding ao IP mitigam replay. WebAuthn usa challenge único por autenticação — replay de uma assinatura não funciona porque o servidor não aceita o mesmo challenge duas vezes.

Pass-the-hash: em ambientes Windows/Active Directory com NTLM, o hash da senha pode ser extraído da memória do processo LSASS (usando Mimikatz ou similar) e usado diretamente em autenticações NTLM sem conhecer a senha em claro. Isso demonstra que hash ≠ seguro quando usado como token de autenticação. Defesas: Credential Guard (protege LSASS com virtualização), desabilitar NTLMv1, migrar para Kerberos ou FIDO2 em ambientes corporativos.

MFA fatigue: adversário automatiza tentativas de login com credenciais válidas (obtidas por phishing ou vazamento), disparando dezenas de push notifications para o usuário. O usuário, frustrado ou distraído, acaba aceitando. Defesas: exibir contexto da requisição no push (localização, app, IP), exigir que o usuário digite um número de correspondência mostrado na tela (number matching), limite de tentativas de MFA por sessão.


Algo que você é — biometria

Biometria é atraente porque não pode ser esquecida nem emprestada facilmente. Mas tem propriedades fundamentalmente diferentes dos outros fatores:

  • Não é revogável: se sua senha vaza, você troca. Se sua impressão digital vaza, você não troca o dedo. Por isso biometria deve ser processada localmente no dispositivo (on-device matching), nunca enviada ao servidor como autenticador primário.
  • Não é secreta: impressões digitais, face e voz são captáveis passivamente por adversários sofisticados. São identificadores únicos, não segredos.
  • Taxa de erro: sistemas biométricos têm FAR (False Acceptance Rate — aceitar impostor) e FRR (False Rejection Rate — rejeitar legítimo). Nenhum é zero. O ponto de operação equilibra os dois.

No modelo FIDO2 / Apple Face ID / Android BiometricPrompt, biometria é usada corretamente: ela desbloqueia a chave privada armazenada no enclave seguro do dispositivo. O servidor nunca vê dados biométricos. O fluxo é:

  1. Biometria verifica: “você é o dono deste dispositivo?”
  2. Enclave libera a chave privada
  3. Chave privada assina o desafio do servidor

Biometria aqui é um fator local de desbloqueio — não um fator transmitido. Isso preserva a privacidade e elimina o risco de vazar o biométrico para o servidor.

Biometria no servidor é anti-padrão

Sistemas que transmitem hash ou template biométrico ao servidor para comparação são perigosos: vazamento do banco expõe dados que o usuário nunca pode revogar. Arquiteturas corretas processam biometria inteiramente no dispositivo e usam o resultado (boolean “verificado”) apenas para liberar uma chave criptográfica local.

Liveness detection: ataques de apresentação (spoofing) com foto, vídeo ou máscara 3D tentam enganar leitores biométricos. Sistemas sérios implementam liveness detection — verificam que o biométrico apresentado pertence a um ser vivo (piscar de olhos, movimento 3D, textura de pele). A qualidade da liveness detection varia enormemente entre implementações.

NIST SP 800-63B sobre biometria: o NIST permite biometria apenas como fator adicional em combinação com “algo que você tem” — nunca como único fator de authN. Essa é a arquitetura que iOS, Android e Windows Hello adotam: biometria desbloqueia o dispositivo, que então executa o protocolo FIDO2. A consequência prática: ao perder um dispositivo com passkey, o adversário ainda precisa passar pela biometria ou PIN local — a chave privada em si não é acessível mesmo com acesso físico ao hardware, dada a proteção do enclave seguro.


Proteção de conta — rate limiting e lockout

Mecanismos de autenticação devem ser protegidos contra tentativas em volume. Sem proteção, brute force e password spraying são viáveis mesmo com senhas razoáveis.

Rate limiting por IP e por conta: limitar tentativas de login por unidade de tempo. Implementar em camadas:

  • Por IP de origem: detecta ataques de spray (1 IP, muitas contas)
  • Por conta: detecta brute force (1 conta, muitas senhas de IPs distribuídos)
  • Global: detecta ataques distribuídos de baixo volume por IP

Lockout progressivo (throttling): após N falhas, aumentar o tempo de espera exponencialmente (1s, 2s, 4s, 30s, 5min, bloqueio temporário). Preferível a bloqueio permanente que pode ser usado como ataque de disponibilidade (adversário bloqueia contas de usuários legítimos propositalmente).

CAPTCHA e desafios: acionar após N tentativas falhas. CAPTCHAs de imagem têm eficácia decrescente contra ML moderno — considerar proof-of-work ou desafios de latência.

Alertas e notificações: notificar o usuário por e-mail ou push quando login ocorre de dispositivo/IP/país novo. Dá visibilidade sobre comprometimento mesmo quando a defesa ativa falha.

Account enumeration: não revelar se o username existe ou não em mensagens de erro. Resposta canônica: “Usuário ou senha incorretos” — nunca “Usuário não encontrado” separado de “Senha incorreta”. Enumerar usuários válidos é o primeiro passo do password spraying. O mesmo princípio se aplica a fluxos de recuperação de senha: “Se esse e-mail existir, você receberá as instruções” — não “E-mail não cadastrado”.

Fluxo de proteção em camadas

Um sistema bem projetado aplica: TLS (canal) → rate limiting por IP (volume) → CAPTCHA após 3 falhas (automação) → lockout progressivo por conta (brute force) → MFA (fator adicional) → alertas de login suspeito (visibilidade). Cada camada compensa a falha da anterior. Nenhuma camada isolada é suficiente — a profundidade de defesa (defense-in-depth) é o princípio que une todas elas, explorado em 04 - Princípios de design seguro.

Credential recovery: o fluxo de recuperação de senha é frequentemente o ponto mais fraco do sistema de autenticação. Se a recuperação acontece só via e-mail sem MFA, ela representa um downgrade do nível de segurança para o nível de segurança da caixa de e-mail. Recovery codes (códigos de backup pré-gerados no momento do registro MFA) e fluxos de verificação de identidade fora de banda são a abordagem correta para contas com MFA.


Sessão após autenticação

Autenticação é um evento pontual. HTTP é stateless — o servidor não “lembra” de requisições anteriores. O sistema precisa de um mecanismo para transportar a prova de autenticação em cada requisição subsequente.

O resultado da autenticação é tipicamente:

  • Cookie de sessão opaco: servidor armazena o estado da sessão (em memória ou banco), o cookie é apenas um identificador aleatório. Revogação é trivial (apagar o registro). Não escala horizontalmente sem store compartilhado (Redis).
  • Token JWT: sessão stateless assinada (HMAC-SHA256 ou RSA). O servidor valida a assinatura sem consultar banco. Revogação é difícil — exige blocklist ou expiração curta.
  • Bearer token OAuth 2.0: acesso delegado — o token representa uma autorização específica, não a identidade completa.

A sessão é o ponto de entrada para 13 - Autorização e controle de acesso: o token carrega (ou permite derivar) as permissões do usuário autenticado — roles, escopos, claims.

Sessão válida ≠ autorizado para tudo

Sessão válida prova que alguém autenticou com sucesso. Não prova que pode executar a ação solicitada. Os dois controles devem ser implementados separadamente em cada endpoint — confundi-los é um erro clássico: if session.valid: do_anything() ignora completamente o controle de acesso granular.


Conexões


Resumo em uma linha

Autenticação é provar identidade com algo que você sabe, tem ou é — e passkeys (FIDO2/WebAuthn) são hoje o único mecanismo que elimina phishing por design, vinculando a credencial à origem e mantendo a chave privada inacessível ao servidor.


Em entrevista

Autenticação é tema recorrente em qualquer entrevista de engenharia com componente de segurança. As perguntas exploram a distinção terminológica, as fraquezas estruturais de senhas, os mecanismos modernos e as decisões de design de sistemas.

Frases úteis em inglês:

  • “Authentication is about proving identity — it answers ‘are you who you claim to be?’ Authorization answers ‘what are you allowed to do?’ They’re distinct layers and must be enforced independently at every endpoint.”
  • “MFA means combining factors from different categories — something you know, have, or are. Two passwords aren’t MFA because if one channel is compromised, the other typically is too.”
  • “Passkeys are phishing-resistant by design because the credential is origin-bound. The authenticator won’t sign a challenge for a domain it wasn’t registered to — the user simply can’t give it to the wrong site.”
  • “The server never sees the private key in WebAuthn. What leaks from a breach is only the public key — cryptographically useless to an attacker without the private key that never left the device.”
  • “NIST 800-63B says don’t force periodic password rotation. Forced rotation produces predictable patterns — users just increment a number or symbol — and doesn’t improve security in practice.”
  • “SMS as a second factor is better than nothing, but it’s vulnerable to SIM swapping and SS7 interception. TOTP or passkeys are the right answer wherever phishing resistance matters.”
  • “Pass-the-hash shows that a hash used directly as an authentication token is as sensitive as the password itself — protecting credentials at rest isn’t just about encryption.”

Vocabulário PT → EN:

PortuguêsInglês
AutenticaçãoAuthentication (authN)
AutorizaçãoAuthorization (authZ)
IdentificaçãoIdentification
Autenticação multifatorMulti-Factor Authentication (MFA)
Algo que você sabe / tem / éSomething you know / have / are
Senha de uso únicoOne-Time Password (OTP)
Vinculado à origemOrigin-bound
Resistente a phishingPhishing-resistant
Troca de SIMSIM swap
Preenchimento de credenciaisCredential stuffing
Pulverização de senhaPassword spraying
Fadiga de MFAMFA fatigue
Token de sessãoSession token / bearer token
Chave pública / privadaPublic / private key
Desafio-respostaChallenge-response
Enclave seguroSecure Enclave / TEE (Trusted Execution Environment)
Autenticação progressiva / step-upStep-up authentication
Descobrível (passkey sem username)Discoverable credential
AtestaçãoAttestation
Parte confiante (servidor)Relying Party (RP)

Lastro