O que é CAPTCHA e por que seu site precisa disso
CAPTCHA (Teste de Turing público totalmente automatizado para distinguir computadores de humanos) é um mecanismo de desafio-resposta que tenta diferenciar usuários reais de scripts automatizados. Soluções modernas vão desde os tradicionais quebra-cabeças de texto distorcido até análise comportamental invisível e desafios interativos, como o slider do GeeTest.
Sem uma camada de CAPTCHA, qualquer formulário público do seu site fica exposto a:
- Credential stuffing — tentativas automatizadas de login usando pares de usuário/senha vazados, comumente vistos em tráfego abusivo.
- Envios de spam — bots inundando formulários de contato, seções de comentários ou páginas de avaliações.
- Enumeração de contas — scripts sondando endereços de e-mail ou nomes de usuário válidos.
- Scraping — extração automatizada de preços, estoque ou conteúdo proprietário.
O trade-off é sempre segurança vs. experiência do usuário: o atrito interrompe bots, mas atrito demais afasta usuários reais. Cloudflare Turnstile e GeeTest v3 são opções modernas que buscam equilibrar esses aspectos: o Turnstile tende à verificação com pouco atrito, enquanto o GeeTest v3 usa um quebra-cabeça interativo de diferentes tipos com checagens baseadas em comportamento para detectar bots.
Como obter seu código de CAPTCHA (chaves e credenciais)
Antes de escrever qualquer código de integração, você precisa de credenciais específicas do provedor.
GeeTest V3
- Crie uma conta no painel do GeeTest.
- Vá para o Captcha Dashboard e selecione CAPTCHA v3:

- Navegue até a seção em que você pode criar um novo CAPTCHA e registrar seu site (normalmente você especifica domínios e o tipo de produto).
- Depois da configuração, você obtém um CAPTCHA ID (frequentemente chamado de gt) e uma Key privada para comunicação no lado do servidor.
- Armazene esses valores com segurança (por exemplo, em variáveis de ambiente) para que sua aplicação possa acessá-los sem hardcodar segredos.
Cloudflare Turnstile
- Faça login em dash.cloudflare.com e abra a seção Application security > Turnstile.

- Clique em Adicionar widget, informe seu domínio e escolha um modo do widget: Managed, Non-interactive ou Invisible.
- Defina Pre-clearance como Yes se o site estiver passando pelo Cloudflare Proxy (para evitar repetir o CAPTCHA).
- Após criar, a Cloudflare fornece uma Site Key (pública, usada no client-side) e uma Secret Key (privada, usada no server-side).
- Use a Site Key no seu HTML ou JavaScript e envie a Secret Key apenas do seu backend ao chamar a API de verificação do Turnstile.
Como implementar GeeTest CAPTCHA v3: passo a passo
O GeeTest v3 usa um fluxo de múltiplas etapas: seu servidor busca um challenge novo no GeeTest, o cliente renderiza o quebra-cabeça usando esse challenge (GeeTest API1) e seu servidor verifica os tokens resolvidos (GeeTest API2). Abaixo há um exemplo em PHP + JavaScript que ilustra esse padrão; adapte-o ao SDK oficial do GeeTest e à linguagem escolhida.
Etapa 1 — Endpoint de registro no lado do servidor
Crie um script PHP (por exemplo, geetest_register.php) que obtenha um challenge novo do GeeTest e o repasse ao cliente:
<?php
header('Content-Type: application/json');
const CAPTCHA_ID = '07df3141a35**19a473d7c50';
const CAPTCHA_KEY = '543b19036ef**8e07d121b81e9';
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
function getJson($url) {
$res = @file_get_contents($url);
return $res ? json_decode($res, true) : null;
}
// API1: Inicialização
if ($path === '/register') {
$data = getJson("https://api.geetest.com/register.php?gt=" . CAPTCHA_ID . "&json_format=1");
echo json_encode($data ? [
'gt' => CAPTCHA_ID,
'challenge' => $data['challenge'],
'success' => $data['success'] === 1,
'new_captcha' => true
] : ['success' => 0]);
exit;
}
// API2: Verificação
if ($path === '/validate' && $_SERVER['REQUEST_METHOD'] === 'POST') {
$req = json_decode(file_get_contents('php://input'), true);
$data = getJson("https://api.geetest.com/validate.php?" . http_build_query([
'seccode' => $req['geetest_seccode'] ?? '',
'challenge' => $req['geetest_challenge'] ?? '',
'gt' => CAPTCHA_ID,
'json_format' => 1
]));
echo json_encode(['success' => !empty($data['seccode'])]);
exit;
}
http_response_code(404);
echo json_encode(['error' => 'Not found']);
?>
Etapa 2 — Inicialização no lado do cliente
Carregue o SDK do GeeTest e chame initGeetest passando os parâmetros vindos do servidor (API1). Exemplo usando ajax:
ajax({
url: "https://example.com/register",
type: "get",
dataType: "json",
success: function (data) {
initGeetest({
gt: data.gt,
challenge: data.challenge,
offline: !data.success,
new_captcha: true
}, function (captchaObj) {
captchaObj.appendTo("#captcha");
captchaObj.onSuccess(function () {
const result = captchaObj.getValidate();
ajax({
url: "https://example.com/validate",
type: "post",
contentType: "application/json",
data: JSON.stringify(result),
success: function(res) {
if (res.success) alert('CAPTCHA passed');
else alert('CAPTCHA failed');
}
});
});
});
}
});
Verificando o funcionamento
Certifique-se de que:
- /register retorna challenge
- O captcha é exibido corretamente
- Após passar pelo captcha, uma requisição para /validate fica visível no console do navegador
- O servidor retorna "success": true
Failback (modo de fallback)
Se o servidor do GeeTest estiver indisponível:
- O cliente recebe success: false
- O captcha muda para local mode (funciona sem conectar à GeeTest Cloud). Para testar isso, basta substituir por um CAPTCHA_ID incorreto (por exemplo, 123456789).
Nota: o GeeTest também oferece SDKs oficiais no lado do servidor para diferentes plataformas e linguagens — você pode escolher o que corresponde ao seu stack de tecnologia. Saiba mais na documentação oficial do GeeTest CAPTCHA v3.
Como implementar Cloudflare Turnstile: passo a passo
O Cloudflare Turnstile não tem uma “chamada de registro” separada no lado do servidor. Você incorpora um widget na sua página, deixa ele gerar um token e depois verifica esse token no lado do servidor usando a API Siteverify da Cloudflare.
Etapa 1 — Conecte o script do Turnstile
Renderização automática (o widget é criado automaticamente quando a página carrega):
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
Controle programático (você cria o widget por conta própria via JavaScript):
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit" defer></script>
Importante: o script precisa ser carregado a partir da URL exata. Proxy ou cache podem causar falhas.
Etapa 2 — Crie um container para o widget
Auto:
<div class="cf-turnstile" data-sitekey="<YOUR_SITEKEY>"></div>
Programaticamente:
<div id="turnstile-container"></div>
Etapa 3 — Configuração do widget
Via atributos data:
<div class="cf-turnstile" data-sitekey="<YOUR_SITEKEY>" data-theme="light" data-size="normal" data-callback="onSuccess"> </div>
Via JavaScript:
const widgetId = turnstile.render("#turnstile-container", {
sitekey: "<YOUR_SITEKEY>",
theme: "light",
size: "normal",
callback: token => console.log("Token:", token)
});
Etapa 4 — Trabalhando com tokens
const token = turnstile.getResponse(widgetId); // get token
const isExpired = turnstile.isExpired(widgetId); // check expiration
turnstile.reset(widgetId); // reset
turnstile.remove(widgetId); // remove
turnstile.execute("#turnstile-container"); // manual execution
Etapa 5 — Integração com o formulário
<form id="my-form" method="POST"> <input type="hidden" name="cf-turnstile-response" id="cf-turnstile-response"> <button type="submit">Submit</button> </form>
<script>
function onSuccess(token) {
document.getElementById("cf-turnstile-response").value = token;
}
</script>
Exemplo completo de código
<html>
<head>
<title>Turnstile Example</title> <!-- Conectar o script do Turnstile -->
<script src="https: //challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</head>
<body>
<h1>Form example with Turnstile</h1>
<form id="my-form"> <label for="username">Name:</label> <input type="text" name="username" id="username" required> <!-- Container para o Turnstile -->
<div class="cf-turnstile" data-sitekey="<YOUR_SITEKEY>" data-callback="onTurnstileSuccess"></div> <button type="submit">Submit</button>
</form>
<script>
// Callback que é chamado após passar pelo CAPTCHA
function onTurnstileSuccess(token) {
console.log("Received Turnstile token:", token);
// Salvar o token em um campo hidden do formulário (opcional)
document.getElementById("cf-turnstile-token")?.remove();
const input = document.createElement("input");
input.type = "hidden";
input.name = "cf-turnstile-response";
input.id = "cf-turnstile-token";
input.value = token;
document.getElementById("my-form").appendChild(input);
}
// Envio do formulário
document.getElementById("my-form").addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const response = await fetch("/submit-form", {
method: "POST",
body: formData
});
const result = await response.json();
if(result.success){
alert("Form successfully submitted and token verified!");
} else {
alert("Turnstile token verification error. Please try again.");
// Resetar o widget para que o usuário possa completar o CAPTCHA novamente
turnstile.reset();
}
});
</script>
</body>
</html>
Etapa 6 — Configure a parte no lado do servidor
Processo de verificação no lado do servidor:
- Cliente: o usuário completa o Turnstile na página → um token é criado.
- O formulário é enviado: o token, junto com os dados do formulário, é enviado ao servidor.
- Servidor: faz uma requisição POST para a API Siteverify da Cloudflare com o token e o secret.
- Cloudflare: retorna um JSON com o resultado (success: true/false) e informações adicionais (action, hostname, completion time).
- Servidor: decide se deve permitir ou rejeitar a ação do usuário.
API Siteverify:
POST
https://challenges.cloudflare.com/turnstile/v0/siteverify
Parâmetros da requisição:
- secret (required): secret Turnstile key do painel da Cloudflare
- response (required): token recebido no cliente
- remoteip (optional): endereço IP do usuário (recomendado)
- idempotency_key (optional): UUID único para proteção contra verificações repetidas
Propriedades do token:
- Tamanho máximo: 2048 caracteres
- Válido por 5 minutos
- De uso único
- Quando expirar ou for verificado novamente, a API retornará o erro timeout-or-duplicate
Exemplo de verificação em PHP:
<?php
function validateTurnstile($token, $secret, $remoteip = null) {
$url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
$data = ['secret' => $secret,
'response' => $token];
if ($remoteip) $data['remoteip'] = $remoteip;
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded
",
'method' => 'POST',
'content' => http_build_query($data)
]
];
$response = file_get_contents($url, false, stream_context_create($options));
if ($response === FALSE) {
return ['success' => false,
'error-codes' => ['internal-error']];
}
return json_decode($response, true);
}
// Usao
$secret_key = 'YOUR_SECRET_KEY';
$token = $_POST['cf-turnstile-response'] ?? '';
$remoteip = $_SERVER['REMOTE_ADDR'];
$result = validateTurnstile($token, $secret_key, $remoteip);
if ($result['success']) {
echo "Form successfully submitted!";
} else {
echo "Verification error: " . implode(', ', $result['error-codes']);
}
?>
Nota: todas as instruções detalhadas para instalar e configurar o Cloudflare Turnstile, incluindo integração no cliente e no servidor, exemplos de código, descrições de erros e recomendações de segurança, podem ser encontradas na documentação oficial da Cloudflare.
Criando um CAPTCHA personalizado: quando e por quê
Um custom captcha é qualquer sistema de desafio-resposta que você constrói por conta própria, em vez de integrar um serviço de terceiros. Abordagens leves comuns incluem:
- Quebra-cabeças matemáticos — "Quanto é 4 + 9?" renderizado como texto simples ou como uma imagem simples gerada.
- Campos honeypot — campos ocultos no formulário que apenas bots tendem a preencher.
- Checagens baseadas em tempo — rejeitar envios concluídos rápido demais para um humano.
- Desafios personalizados com imagem — "Clique no item que não pertence" usando seus próprios assets.
CAPTCHAs personalizados podem ser úteis quando você precisa de controle rígido de branding, quando requisitos estritos de privacidade limitam scripts de terceiros ou quando seu perfil de risco é baixo e você só precisa de um atrito básico contra bots. No entanto, eles normalmente não têm os modelos comportamentais sofisticados de serviços como GeeTest ou Turnstile e podem ser mais fáceis de derrotar por bots avançados.
Você também assume total responsabilidade por acessibilidade (por exemplo, fornecer alternativas de áudio) e pela manutenção contínua conforme as técnicas de bots evoluem. Para fluxos críticos como login, checkout ou redefinição de senha, uma solução gerenciada geralmente é mais segura do que um custom captcha totalmente próprio.
Como bloquear bots de CAPTCHA de forma eficaz
Implementar CAPTCHA é necessário, mas raramente é suficiente por si só; atacantes determinados vão tentar burlá-lo ou automatizá-lo. Para bloquear captcha bots com mais eficácia, combine múltiplas camadas.
Camada 1 — Rate Limiting no nível de infraestrutura
Rate limiting no seu servidor web ou CDN torna mais difícil para bots fazerem brute force em formulários, mesmo que consigam resolver ou burlar captchas. Por exemplo, em Nginx:
# Nginx: limitar o endpoint de login a 10 req/s por IP
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/s;
location /login {
limit_req zone=login burst=5 nodelay;
# proxy_pass ...
}
Camada 2 — Campos honeypot
Um campo oculto que usuários reais nunca veem, mas que bots pouco sofisticados podem preencher, é uma defesa de baixo atrito.
<div aria-hidden="true">
<input type="text" name="website" tabindex="-1" autocomplete="off">
</div>
No servidor, rejeite qualquer envio em que website não esteja vazio. Isso quase não adiciona custo de UX, ao mesmo tempo em que filtra uma parte dos envios automatizados.
Camada 3 — Camadas adicionais de defesa
- Filtragem por reputação de IP: bloquear faixas conhecidas de datacenter ou serviços de anonimização na borda pode reduzir significativamente o tráfego abusivo.
- Prevenção de replay de token: tokens do Turnstile devem ser validados no lado do servidor e tratados como de uso único; descartar tokens reutilizados ajuda a prevenir ataques de replay.
- Fingerprinting de dispositivo ou sessão: ferramentas externas podem ajudar a correlacionar padrões suspeitos entre IPs e sessões, embora introduzam considerações de privacidade.
- Monitoramento e alertas: acompanhe taxas de falha de verificação e picos repentinos de tráfego de determinadas regiões ou ASNs como sinais de um ataque em andamento.