# 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](https://ikiform.com/pt-br/docs/rate-limits.md) | Sim, preset Standard | `429 rate_limited` |
| [Domínios permitidos](#allowed-domains) | Não | Spam, ou `403 origin_not_allowed` |
| [Verificação humana](#human-check) | Não | `403 challenge_required` ou uma página de verificação |
| [Honeypot](#honeypot) | Sim | +5 na pontuação |
| [Pontuação de spam](#scoring) | 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](https://ikiform.com/pt-br/docs/api.md#mark-spam); 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](https://ikiform.com/pt-br/docs/html.md#honeypot).

`Honeypot`:

```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](https://ikiform.com/pt-br/docs/shadcn.md), que enviam um `_ikiform_ts` assinado. Envios HTML simples sem ele não são penalizados.
- Um campo de nome é qualquer campo cujo nome contém `name`, `firstname`, `lastname`, `fullname`, `surname` ou `subject`, mas não palavras como `company`, `website` ou `domain`.
- Dois motivos forçam spam independentemente da pontuação: `origin_mismatch`, dos [domínios permitidos](#allowed-domains), e `captcha_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

A forma de obter o token depende de como você envia:

- **Envio de formulário HTML:** o envio sem token recebe uma página curta "Checking you're human" em ikiform.com. Ela roda o Turnstile e envia os campos originais de novo com o token, e então o navegador segue o seu redirecionamento normalmente.
- **JavaScript:** chame `challenge(formId)` do SDK. Ele monta um pequeno frame de ikiform.com que fica invisível, a menos que o Turnstile precise de um clique, e resolve com um token. Passe-o para `submit` como `turnstileToken`. Um envio com `fetch` sem token recebe `403 challenge_required`.
- **Componente shadcn/ui:** resolvido para você.
- **Servidor com chave secreta:** a verificação é ignorada, já que um servidor não consegue resolvê-la.

`form.js`:

```js
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`.

`403 Forbidden`:

```json
{
  "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"
}
```

> Se o próprio Turnstile não puder ser acessado, o envio é aceito e armazenado como spam com o motivo `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](https://ikiform.com/pt-br/docs/rate-limits.md).
