hCaptcha com PHP
Protegendo formulário de seu site contra spam/bots com hCaptcha

Thiago Bomfim
18/07/2025 18h49
O hCaptcha é uma ferramenta que auxilia serviços online a se proteger contra ataques de bots, spam e outros abusos. Nesse artigo, implementaremos o hCaptcha com PHP num formulário de login como exemplo.
Há alguns programas de computadores (bots) construídos para atacar sites. Esse ataques tem como principais objetivos enviar spam, invadir alguma conta ou indisponibilizar algum serviço do seu site. Nesse contexto, podemos utilizar o CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) para criar uma camada de segurança no site. O CAPTCHA consiste em criar um desafio capaz de distinguir se o serviço do site está sendo requisitado por um ser humano ou um bot.
O hCapctha é um dos serviços que permite que essa camada de segurança seja implementada no site, realizando perguntas que facilmente são interpretadas por ser humanos, mas difíceis para um bot.
Vâmos implementar o hCaptcha num formulário de login como exemplo. Antes de começar a implementação, verifique se seu ambiente de desenvolvimento atendem aos seguintes requisitos:
- necessário que o PHP esteja instalado em seu computador;
- ajustar seu host domínio no localhost: https://docs.hcaptcha.com/#local-development;
- Por aqui, ajustei meu domínio em /etc/hosts com 127.0.0.1 tutorials.local
No Frontend, utilizaremos o template formulário de login Bootstrap (https://getbootstrap.com/docs/5.3/examples/sign-in/). Crie um diretório chamado tutorials, e dentro deste diretório, crie outro diretório chamado captcha-com-php. Dentro do diretório captcha-com-php, crie um arquivo html index.html com o conteúdo html extraído do template Bootstrap. Substitua a tag <main> pelo conteúdo abaixo:
<main class="form-signin w-100 m-auto">
<div class="ajax_response pb-4"></div>
<form id="login" action="./hcaptcha-com-php/login.php" method="POST">
<h1 class="h3 mb-3 fw-normal">Login</h1>
<div class="form-floating">
<input type="email" class="form-control" id="floatingInput" placeholder="Digite seu email" name="email">
<label for="floatingInput">Email</label>
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" placeholder="Digite a Senha" name="pwd">
<label for="floatingPassword">Senha</label>
</div>
<div class="h-captcha" data-sitekey="your_site_key"></div>
<button class="btn btn-primary w-100 py-2" type="submit">Entrar</button>
</form>
</main>
<script src="https://js.hcaptcha.com/1/api.js?hl=pt" async defer></script>
É necessário incluir o recurso JavaScript hCaptcha em algum lugar da index.html, observe que eu incluí-o logo após a tag <main>, configurada para a linguagem Português (hl=pt):
<script src="https://js.hcaptcha.com/1/api.js?hl=pt" async defer></script>
Também inserir uma seção na qual o html hCaptcha será renderizada:
<div class="h-captcha" data-sitekey="your_site_key"></div>
No atributo data-sitekey="your_site_key" deve ser inserido sua chave configurada no cadastro em captcha.
Agora, dentro do diretório tutorials criado anteriormente, rode um servidor PHP pelo terminal com o seguinte comando: sudo php -S 127.0.0.1:80
Esse comando permite que um servidor Web seja ativado na porta 80, e nosso domínio configurado será direcionado para essa porta, assim podemos rodar os projetos dentro do diretório tutorials. No nosso ambiente de desenvolvimenmto a url http://tutorials.local/hcaptcha-com-php/ já possibilita executar a página index.html.

Agora implementaremos uma chamada JavaScript para quando o botão Entrar for clicado. Insira no fina da tag </body> o seguinte trecho de código JavaScript:
<script>
const getAjaxRequest = () => {
var Ajax;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
Ajax = new XMLHttpRequest();
} else {// code for IE6, IE5
Ajax = new ActiveXObject("Microsoft.XMLHTTP");
}
return Ajax;
}
const checkCaptcha = (form) => {
var captchaResponse = form.elements['h-captcha-response'].value;
return captchaResponse ? true : false;
}
var form = document.getElementById('login');
form.addEventListener("submit", (event) => {
event.preventDefault();
var ajaxResponseMessage = document.querySelector('.ajax_response');
var captcha = checkCaptcha(form);
if (!captcha) {
ajaxResponseMessage.innerHTML = 'Verifique se você é humano.';
return;
}
var request = getAjaxRequest();
var formData = new FormData(form);
var AjaxContact = getAjaxRequest();
AjaxContact.open('POST', form.action, true);
AjaxContact.send(formData);
AjaxContact.onreadystatechange = () => {
if (AjaxContact.readyState == 4 && AjaxContact.status == 200) {
var response = JSON.parse(AjaxContact.responseText);
ajaxResponseMessage.innerHTML = response.message;
if (response.status == 'SUCCESS') {
form.reset();
}
if (response.status == 'DATA_FAIL') {
}
}
};
});
</script>
Esse trecho de código JavaScript é responsável por processar uma Request para o arquivo ./login.php que inserimos na action do formulário. Em instantes criaremos esse arquivo. Não se preocupe por agora em entender o código JavaScript, podemos em outro momento produzirmos um tutorial de chamada JavaScript Ajax.
Podemos agora criar o script que vai processar a Request oriundo do formulário da página de index.html. No diretório captcha-com-php, crie um arquivo login.php, que será responsável por processar a Request, validando se o token no desafio hcaptcha é realmente válido.
<?php
try {
$check = checkRequest($_POST);
if (!$check) {
return;
}
$verify = curl_init();
$checkCaptcha = (new HCaptcha())->verify($_POST['h-captcha-response']);
if ($checkCaptcha) { // aqui pode prosseguir com a validação de email e senha
jsonResponse(['status' => 'SUCSESS', 'message' => 'Login realizado com sucesso.']);
return;
} else {
jsonResponse(['status' => 'DATA_FAIL', 'message' => 'Falha nos dados, recarregue a página e tente novamente.']);
return;
}
} catch (\Throwable $th) {
jsonResponse(['status' => 'DATA_FAIL', 'message' => $th->getMessage()]);
return;
}
function jsonResponse(array $dataResponse): void {
echo json_encode($dataResponse);
}
function checkRequest(array &$request): bool {
if (empty($request['email']) || empty($request['pwd'])) {
jsonResponse(['status' => 'DATA_FAIL', 'message' => 'Preencha os campos.']);
return false;
}
if (empty($request['h-captcha-response'])) {
jsonResponse(['status' => 'DATA_FAIL', 'message' => 'Erro ao enviar, favor check se você é humano']);
return false;
}
return true;
}
class HCaptcha
{
private string $apiURL = 'https://api.hcaptcha.com/siteverify';
private string $secret = 'YOUR-SECRET'; // YOUR-SECRET é obtido no seu cadastro
public function __construct() {
}
public function verify(string $codeResponse): bool
{
$data = array(
'secret' => $this->secret,
'response' => $codeResponse,
'remoteip' => $_SERVER['REMOTE_ADDR']
);
$verify = curl_init();
curl_setopt($verify, CURLOPT_URL, $this->apiURL);
curl_setopt($verify, CURLOPT_POST, true);
curl_setopt($verify, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($verify, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($verify);
$responseData = json_decode($response);
if($responseData->success) {
return true;
}
return false;
}
}
Quando no Frontend o desafio é processado, é criado no formulário um input chamado h-captcha-response com um token que é utilizado na API hCaptcha para validar o desafio. Nesse fluxo, é necessário inserir sua chave em YOUR-SECRET obtida no cadastro hCaptcha.
Temos uma Classe HCaptcha responsável por processar a validação por meio da API hCaptcha https://api.hcaptcha.com/siteverify, que deve ser requisitada num HTTP POST. Em caso de sucesso na resposta, prosseguimos com o fluxo, caso contrário, o fluxo é interrompido.
Vejamos como ficou a renderização do desafio:

Vejamos como ficou o fluxo realizado com sucesso:

A implementação pode ser aplicada num projeto MVC (Model-View-Controller).
O código está disponível no GitHub aqui
Conclusão
Os ataques à sites ocorrem e é inevitável. Para proteger seu site é necessário implantar camadas de seguranças nos fluxos de requisições do site para detectar possíveis ataques e bloquear. O hCaptcha é uma dessas camadas, que cria mecanismos para distinguir humanos de bots nos formulários.
Fontes: