Proteção contra spam
Honeypot, timestamps assinados, pontuação de spam, verificação humana, domínios permitidos e limites de taxa.
Todo formulário ganha proteção em camadas sem configuração: um honeypot, um timestamp de renderização assinado, pontuação de spam e limites de taxa. Além disso, você pode adicionar uma verificação humana e restringir o formulário aos seus próprios domínios.
| Camada | Ativa por padrão | Resultado |
|---|---|---|
| Limites de taxa | Sim, preset Standard | 429 rate_limited |
| Domínios permitidos | Não | Spam, ou 403 origin_not_allowed |
| Verificação humana | Não | 403 challenge_required ou uma página de verificação |
| Honeypot | Sim | +5 na pontuação |
| Pontuação de spam | Sim | Spam a partir de 5 |
Como o spam é tratado
Um envio considerado spam é armazenado com o status spam e ainda recebe uma resposta de sucesso normal, então os bots não aprendem nada. Spam não dispara webhooks nem e-mails, não conta no seu uso mensal e é excluído após 30 dias. Revise no painel ou com a API REST; marcar um envio como não spam dispara os webhooks dele nesse momento.
Honeypot
Adicione um input oculto que as pessoas nunca preenchem. O nome padrão é _gotcha; você pode mudá-lo por formulário em Honeypot field, nas configurações do formulário. As técnicas para escondê-lo estão em Formulários HTML.
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />Pontuação de spam
Cada envio recebe uma pontuação a partir destes sinais. Com 5 ou mais, ele é armazenado como spam.
| Sinal | Motivo no painel | Pontuação |
|---|---|---|
| O honeypot foi preenchido | honeypot | +5 |
| Enviado menos de 2 segundos depois de o formulário ser renderizado | timestamp_fast | +3 |
| O timestamp de renderização assinado é falso ou tem mais de 24 horas | timestamp_invalid | +3 |
| Um link em um campo de nome ou assunto | url_in_name | +3 |
| Os mesmos campos foram enviados para este formulário nas últimas 24 horas | duplicate | +3 |
| Três ou mais links no total | many_urls | +2 |
| Uma frase de spam conhecida (22 embutidas) | keyword | +2 |
| Um endereço de e-mail em um domínio de e-mail descartável | disposable_email | +2 |
- O timestamp de renderização só existe quando o formulário é renderizado pelo SDK ou pelo componente shadcn/ui, que enviam um
_ikiform_tsassinado. Envios HTML simples sem ele não são penalizados. - Um campo de nome é qualquer campo cujo nome contém
name,firstname,lastname,fullname,surnameousubject, mas não palavras comocompany,websiteoudomain. - Dois motivos forçam spam independentemente da pontuação:
origin_mismatch, dos domínios permitidos, ecaptcha_unavailable, quando o Turnstile não pode ser acessado.
Verificação humana
Cada formulário tem uma configuração Spam check com três opções. Ela vem desativada por padrão, então integrações existentes com fetch e curl continuam funcionando quando você cria um formulário.
| Opção | O que faz |
|---|---|
| Off (desativada) | Sem desafio. Honeypot, timestamp e pontuação continuam rodando. |
| Ikiform (recomendado) | Cloudflare Turnstile rodado pelo Ikiform em ikiform.com. Não precisa de conta nem de chaves da Cloudflare. |
| Your own Turnstile keys (suas próprias chaves) | O seu widget e a sua secret key do Turnstile. O hostname do token é comparado aos seus domínios permitidos. |
Como a verificação do Ikiform roda
Formulário HTML
- O navegador envia o formulário
- Ainda sem token: ikiform.com mostra uma página de verificação rápida
- O Turnstile roda e a página envia os mesmos campos de novo com um token
- 303 para o seu redirecionamento ou para a página de agradecimento
JavaScript
- challenge(formId) monta um frame oculto de ikiform.com
- O Turnstile roda e só aparece se precisar de um clique
- submit(formId, data, { turnstileToken })
- 201 com o id do envio
Servidor com chave secreta
- POST com Authorization: Bearer ik_sk_...
- A verificação do Ikiform é ignorada
- 201 com o id do envio
import { challenge, submit } from "@ikiform/sdk";
const form = document.querySelector("form");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const turnstileToken = await challenge("frm_xxxxxxxxxxxxxxxx");
const result = await submit("frm_xxxxxxxxxxxxxxxx", new FormData(form), { turnstileToken });
if (result.ok) form.replaceWith("Thanks, we got it.");
});Os tokens são de uso único e valem por 300 segundos, então obtenha um por envio. Um envio JSON sem token recebe 403 challenge_required com um challenge_url; um token que falha na verificação recebe 403 captcha_failed.
{
"ok": false,
"error": {
"code": "challenge_required",
"message": "Complete the human check, then send the form again.",
"challenge_url": "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx/challenge"
},
"request_id": "req_01k7v2c9t3e8m5q4x6z0a1b2c3"
}captcha_unavailable, para que você possa restaurá-lo em vez de perdê-lo.Your own Turnstile keys (suas próprias chaves)
Cole a sua site key e a sua secret key nas configurações do formulário. O segredo é criptografado em repouso. Renderize o widget no seu formulário para que ele adicione cf-turnstile-response ao envio, ou passe o token para submit como turnstileToken. Envios sem um token válido recebem 403 captcha_failed, inclusive envios com uma chave de API secreta.
Domínios permitidos
Liste os domínios onde o seu formulário fica em Allowed domains. A partir daí, um envio precisa vir de um deles ou de um subdomínio, avaliado pelo header Origin, ou pelo Referer quando não há origem. Deixe a lista vazia para aceitar envios de qualquer site.
| Domínios permitidos | Envio de | Corresponde |
|---|---|---|
example.com | https://example.com | Sim |
example.com | https://www.example.com | Sim, subdomínio |
example.com | http://localhost:3000 | Não, adicione localhost durante o desenvolvimento |
example.com | https://example.co | Não |
app.example.com | https://example.com | Não, um domínio pai não corresponde |
When a post comes from another site define o que acontece quando não há correspondência: Mark as spam (o padrão) ou Reject com 403 origin_not_allowed. Envios com uma chave de API secreta pulam esta verificação. Os domínios permitidos também definem quais destinos de _redirect são seguidos e onde o frame de verificação do Ikiform pode ser incorporado.
Limites de taxa
Cada formulário tem um preset de Rate limit, contado exatamente por IP de visitante e formulário. Standard permite 5 envios por minuto, Relaxed 20 por minuto e Strict 2 a cada 10 minutos. As regras completas estão em Limites de taxa.