Korzen
Bot Protection

Proteger um checkout

Rotas de pagamento, login e cadastro: exija o token da tag em Node, Go, Python, PHP, Java, .NET ou num Cloudflare Worker, comece no modo monitor e saiba quem isso barra.

Teste de cartões (card testing) é um script que tenta cartões roubados com pagamentos pequenos, um atrás do outro, para descobrir quais ainda funcionam. Em geral o script nunca carrega a sua página. A tag nunca roda, então a decisão não tem nenhum sinal de um navegador, e a classe é unknown, que é liberada. A falta de um sinal nunca é evidência de bot, então o Bot Protection não o chama assim. Nas ações que esse script procura, peça a prova de uma visita de verdade: o token da tag.

O que o requireToken faz

Com "require_token": true na chamada (a opção requireToken dos SDKs, em Go RequireToken), a ação só segue com um token válido obtido pela tag naquele navegador. Sem ele, a resposta é challenge com token_required true, qualquer que seja a classe; a classe em si não muda. O envio do formulário gasta o token, uma vez por sessão e por rota a cada hora; até três tentativas em dois minutos são a mesma tentativa, então um cartão recusado e um segundo cartão ainda passam. Um carregamento de página (GET, HEAD) não gasta token, e os SDKs enviam a opção só nas ações. As regras completas: uma ação que precisa da tag.

Coloque a tag na página onde cada ação começa: a página de checkout, a de login, a de cadastro. A tag

Quais rotas

  • Pagamento: o envio que cobra o cartão ou fecha o pedido, e qualquer um que adicione um cartão ou resgate um vale-presente. Teste de cartões.
  • Login: o envio que confere a senha. Credential stuffing.
  • Cadastro: o envio que cria a conta. Contas falsas.

Deixe de fora as rotas às quais nenhuma página sua leva: os webhooks do seu provedor de pagamento, a API do seu app mobile, o servidor de um parceiro. Nenhuma tag roda ali, então toda requisição receberia desafio.

No seu código

Cada aba acrescenta a opção à chamada que o guia do framework monta. Node e Go usam a opção do arquivo cliente que a Korzen serve; os outros enviam o campo no corpo da chamada.

Node

// Express, with korzen.js as the Express guide sets it up
const guard = protect({ client: korzen, ip: (_get, req) => req.ip, requireToken: true });

app.get("/checkout", guard, showCheckout); // the page: a page load spends no token
app.post("/checkout", guard, placeOrder); // the action: it needs the tag's token

// Next.js, Hono or any handler of a Web Request
export const POST = withKorzen(placeOrder, { client, ip: ipFrom.vercel, requireToken: true });

Go

mux.Handle("POST /checkout", bot.Protect(http.HandlerFunc(placeOrder), korzen.Options{
	IP:           korzen.RemoteIP,
	RequireToken: true, // the action needs the tag's token
}))

Python

# In decide() of the Django and Flask or FastAPI guide: one more field in the body.
json={
    # ...the fields the guide sends
    "path": path,
    "method": "POST",
    "require_token": True,  # on payment, login and sign-up
},

PHP

// In decide() of the PHP or Laravel guide: one more field in the body.
'path' => $path,
'method' => 'POST',
'require_token' => true, // on payment, login and sign-up

Java

// In decide() of the Spring Boot guide: one more field in the body.
body.put("path", path);
body.put("method", "POST");
body.put("require_token", true); // on payment, login and sign-up

.NET

// In Decide() of the ASP.NET Core guide: one more field in the body.
["path"] = path,
["method"] = "POST",
["require_token"] = true, // on payment, login and sign-up

Ruby

# In decide of the Rails guide: one more field in the body.
path: path,
method: "POST",
require_token: true # on payment, login and sign-up

Cloudflare Worker

# wrangler.toml: the paths whose actions need the tag's token, by commas;
# one ending in * is a prefix.
[vars]
KORZEN_REQUIRE_TOKEN = "/checkout,/login,/signup"

Quando a mesma função pergunta por todas as ações, dê a ela a escolha: passe true dos handlers de pagamento, login e cadastro e false dos demais. Um campo com erro de digitação, como requireToken no corpo, é recusado com 400 e deixa o visitante passar, como todo erro: confira as primeiras respostas.

Primeiro o modo monitor

Ligue a opção enquanto a conta está no modo monitor. A action de toda resposta continua allow, então ninguém é barrado; uma ação que chegou sem token responde intended_action challenge com token_required true. Acompanhe dois números por alguns dias:

  • as decisões nessas rotas com token_required true, nas respostas que o seu servidor registra;
  • a parcela Sem token na saúde da integração, na página Configuração. Uma parcela alta ali costuma indicar uma página que leva à ação sem a tag, ou um formulário enviado antes de a tag rodar: corrija isso primeiro.

O que sobra é sobretudo script, e algumas pessoas cujo navegador não roda a tag (abaixo). Ligue o modo bloqueio quando essa parcela for aceitável para você. Modo monitor e modo bloqueio

As ações de cada classe

O padrão serve para um checkout. A ação da classe e o token são coisas separadas: com um token válido, a ação é a da classe; sem ele, é no mínimo challenge.

ClasseAçãoNum checkout
human highallowsiga
humanallowsiga
unknownallowsiga: com o token exigido, um script que pulou a sua página recebe challenge
botchallengea sua própria verificação, como 3-D Secure ou um código por email, ou a nossa página de desafio a partir da página de checkout
bot highblockrecuse com a mensagem de um cartão recusado, para o script não aprender nada

Com a isca ligada para bot e bot_high na página Configuração, os SDKs respondem sozinhos a uma ação com isca, com algo que parece sucesso, para o script não aprender nada. Uma resposta isca

Depois do pagamento, envie o resultado do seu provedor de pagamento como feedback: um chargeback ou uma fraude confirmada pesam contra as próximas decisões daquele navegador, um bom cliente pesa a favor.

Quem isso barra

Um visitante cujo navegador não roda a tag não tem token: um bloqueador de anúncios ou uma extensão de privacidade que a bloqueia, um filtro de DNS que bloqueia o host da API do Bot Protection, o JavaScript desligado. Numa rota com require_token, no modo bloqueio, esse visitante recebe desafio na ação. A nossa página de desafio pede uma pequena prova de trabalho e que a nossa tag rode ali. Com o JavaScript desligado não há como passar, e um filtro de DNS que bloqueia o nosso host bloqueia a página também. Essa pessoa não consegue pagar, a menos que você ofereça outro caminho.

  • Envie a opção nas rotas em que um script custa mais do que uma pessoa barrada: pagamento, login, cadastro. Nunca em todas as rotas.
  • Leia a parcela no modo monitor antes de ligar o modo bloqueio, como acima.
  • Sob challenge, ofereça um caminho que não precise da nossa tag, se você tiver um: 3-D Secure, um código por email ou telefone, um contato do suporte. O hook onChallenge dos SDKs o executa no lugar do redirecionamento.

Quando o Bot Protection está lento ou fora do ar, o seu servidor deixa o visitante passar, com token ou sem: a chamada é fail-open.