CAPTCHA (“Completely Automated Public Turing test to tell Computers and Humans Apart”) é um teste projetado para ser fácil para humanos e difícil para máquinas. Na prática, é a ferramenta mais comum para reduzir a automação abusiva em formulários: cadastros em massa, credential stuffing, spam de comentários, brute-force de login e abuso de cupons. Mas há muita confusão sobre o que ele garante. Vamos separar o que é mito do que é defesa real.

A tese central deste artigo: CAPTCHA aumenta o custo do ataque automatizado — ele não autentica, não autoriza e não substitui as outras camadas.

Como o CAPTCHA moderno funciona

As soluções atuais quase não mostram “quebra-cabeças” e dependem de sinais de comportamento e reputação do navegador. O fluxo, em qualquer uma delas, é sempre o mesmo:

  1. O navegador carrega um widget do provedor e coleta sinais (movimento, histórico, reputação de IP, fingerprint).
  2. O provedor devolve um token opaco para o cliente.
  3. O formulário envia esse token junto com os demais campos.
  4. O seu servidor valida o token chamando a API do provedor. Este passo é o que realmente importa.

As opções mais usadas

  • reCAPTCHA v2 (“Não sou um robô” / seleção de imagens): desafio visível quando o risco é alto.
  • reCAPTCHA v3: invisível, devolve um score de 0.0 a 1.0; você decide o limiar e a ação (bloquear, pedir MFA, exigir um v2).
  • hCaptcha: alternativa com foco em privacidade, modelo de desafio semelhante ao v2.
  • Cloudflare Turnstile: invisível, sem quebra-cabeças, sem rastreamento cross-site — popular justamente por equilibrar UX e privacidade.

O erro número um: não validar o token no servidor

A falha mais comum que encontramos em pentests é simples e fatal: o site mostra o widget, recebe o token, e nunca o valida no backend — ou valida só no JavaScript do cliente. Como o atacante controla totalmente a requisição que sai do “cliente”, ele simplesmente omite ou falsifica o campo do token e envia o formulário direto para o servidor. O CAPTCHA vira decoração.

A validação correta é server-side, contra a API do provedor:

import requests

def captcha_valido(token, ip_cliente):
    r = requests.post(
        "https://challenges.cloudflare.com/turnstile/v0/siteverify",
        data={
            "secret": SECRET_KEY,      # segredo do servidor, NUNCA no front
            "response": token,         # token recebido do formulário
            "remoteip": ip_cliente,
        },
        timeout=5,
    )
    data = r.json()
    return data.get("success") is True

@app.post("/login")
def login():
    if not captcha_valido(request.form.get("cf-turnstile-response"), request.remote_addr):
        abort(403)   # rejeita ANTES de processar o login
    # ... segue o fluxo normal

Pontos críticos dessa validação:

  • O secret fica só no servidor. Se vazar para o front, o esquema inteiro cai.
  • Verifique também os campos que o provedor retorna: hostname (precisa ser o seu domínio), action (no reCAPTCHA v3) e o timestamp do desafio.
  • Cada token é de uso único e expira. Rejeite tokens reutilizados e expirados — senão o atacante resolve um desafio uma vez e replica o token mil vezes.
  • Para o v3, defina um limiar de score e uma ação para a zona cinzenta (ex.: score < 0.5 → exigir reCAPTCHA v2 ou MFA, não bloquear de imediato).

Onde encaixar o CAPTCHA — e onde não

Coloque CAPTCHA onde há automação de alto valor:

  • Login (especialmente após algumas falhas — CAPTCHA adaptativo).
  • Cadastro / criação de conta.
  • Reset de senha (também ajuda contra enumeração em massa).
  • Formulários públicos de contato/comentário (spam).
  • Endpoints caros ou que disparam e-mail/SMS (evita abuso de custo).

Evite CAPTCHA onde ele só atrapalha: em todas as páginas, em cada clique autenticado, ou como única barreira de uma API consumida por outros sistemas (lá, use chaves de API, mTLS e rate limiting).

Os bypasses — por que CAPTCHA sozinho não basta

Nenhum CAPTCHA é inquebrável. Os contornos reais:

  • CAPTCHA farms: serviços humanos que resolvem desafios por centavos, via API. Para um atacante motivado, é só um custo operacional.
  • Solvers automatizados: modelos de visão e áudio resolvem boa parte dos desafios visuais e sonoros.
  • Reuso/replay de token: se o servidor não invalida o token após o uso, um único desafio resolvido vira N requisições.
  • Ausência de verificação de hostname: o atacante resolve o CAPTCHA no seu próprio site (com a mesma site key, se exposta) e usa o token no alvo.
  • Roubo de token via XSS/man-in-the-middle: se há outra falha na página, o token pode ser capturado.

A lição: o CAPTCHA eleva o custo, mas um adversário determinado paga esse custo. Ele precisa de reforço.

Acessibilidade e UX: o custo do lado humano

CAPTCHAs visuais excluem usuários — pessoas com deficiência visual, daltônicos, quem usa leitor de tela. Boas práticas:

  • Prefira soluções invisíveis/adaptativas (Turnstile, reCAPTCHA v3) que só desafiam sob suspeita.
  • Sempre ofereça uma alternativa de áudio quando houver desafio visual.
  • Garanta navegação por teclado e rótulos ARIA adequados.
  • Meça o atrito: CAPTCHA agressivo derruba conversão tanto quanto bots.

CAPTCHA é uma camada — a defesa em profundidade

CAPTCHA deve compor uma estratégia, não ser ela:

  • Rate limiting por IP, conta e identificador — a primeira e mais importante barreira contra automação.
  • Lockout / backoff progressivo após falhas de login.
  • MFA — anula o valor de credenciais roubadas, mesmo que o bot passe.
  • Detecção de credential stuffing (senhas vazadas conhecidas, reputação de IP/ASN).
  • WAF / bot management para padrões de tráfego anômalos.
  • Verificação por e-mail/telefone em fluxos sensíveis.

Pensar nessas camadas em conjunto é o que separa “tem um CAPTCHA” de “resiste a automação”.

Como testamos a proteção de formulários

  1. Submeter o formulário sem o token e com token inválido/vazio — o servidor rejeita?
  2. Reutilizar um token válido em várias requisições — ele é invalidado após o primeiro uso?
  3. Resolver o CAPTCHA em outro domínio e usar o token no alvo — há checagem de hostname?
  4. Avaliar o rate limiting por trás do CAPTCHA: removido o widget, a automação volta a ser trivial?
  5. Conferir se o secret não vaza no front e se a verificação acontece antes da ação sensível.

Checklist de mitigação

  • Validar o token no servidor, contra a API do provedor, antes de processar a ação.
  • secret apenas no backend; nunca confiar em verificação client-side.
  • Conferir success, hostname, action/score e expiração do token.
  • Token de uso único — rejeitar replay.
  • CAPTCHA adaptativo nos pontos de alto valor, não em tudo.
  • Combinar com rate limiting, lockout, MFA e detecção de credential stuffing.
  • Garantir acessibilidade (alternativa de áudio, teclado, ARIA).

CAPTCHA é uma boa ferramenta mal compreendida. Ele não diz que do outro lado há um humano de confiança — diz, no máximo, que automatizar ficou mais caro. Tratado como uma camada de uma defesa em profundidade, ele cumpre bem seu papel. Tratado como a defesa inteira, é uma falsa sensação de segurança que um pentest derruba em minutos.