Assine para receber notificações de novos posts:

Integração do Turnstile com o Cloudflare WAF para desafiar solicitações de busca

2023-12-18

4 min. de leitura
Este post também está disponível em English, 繁體中文, Français, Deutsch, 日本語, 한국어, Español, Polski e 简体中文.

Há dois meses, colocamos o Cloudflare Turnstile em disponibilidade geral, oferecendo aos proprietários de sites em todos os lugares uma maneira fácil de se defender de bots, sem nunca emitir um CAPTCHA. O Turnstile permite que qualquer proprietário de site incorpore um desafio da Cloudflare sem frustrações em seu site com um simples snippet de código, facilitando a garantia de que apenas o tráfego humano passe. Além de proteger o front-end de um site, o Turnstile também capacita os administradores da web a fortalecer as chamadas de API iniciadas pelo navegador (AJAX) em execução nos bastidores. Essas APIs são comumente usadas por aplicativos web dinâmicos de página única, como aqueles criados com React, Angular, Vue.js.

Integrating Turnstile with the Cloudflare WAF to challenge fetch requests

Hoje, temos o prazer de anunciar que integramos o Turnstile ao firewall de aplicativos web (WAF) da Cloudflare. Isso significa que os administradores da web podem adicionar o snippet de código Turnstile aos seus sites e, em seguida, configurar o WAF da Cloudflare para gerenciar essas solicitações. Isso é totalmente personalizável usando regras WAF. Por exemplo, você pode permitir que um usuário autenticado pelo Turnstile interaja com todos os endpoints de API de um aplicativo sem enfrentar mais desafios, ou pode configurar certos endpoints confidenciais, como Login, para sempre emitir um desafio.

Desafiar solicitações de busca no Cloudflare WAF

Milhões de sites protegidos pelo WAF da Cloudflare aproveitam nosso Desafio JS, Desafio gerenciado e Desafio interativo para parar bots e permitir a passagem de humanos. Para cada um desses desafios, a Cloudflare intercepta a solicitação correspondente e responde com uma página HTML renderizada pelo navegador, onde o usuário conclui uma tarefa básica para demonstrar que é humano. Quando um usuário conclui um desafio com sucesso, ele recebe um cookie cf_clearance, que informa à Cloudflare que um usuário passou com sucesso em um desafio, o tipo de desafio e quando ele foi concluído. Um cookie de autorização não pode ser compartilhado entre usuários e só é válido pelo tempo definido pelo cliente da Cloudflare em seu painel de configurações de segurança.

Esse processo funciona bem, exceto quando um navegador recebe um desafio em uma solicitação de busca e o navegador ainda não passou no desafio.  Em uma solicitação de busca ou solicitação XML HTTP (XHR), o navegador espera receber texto simples (nos formatos JSON ou XML) e não pode renderizar o HTML necessário para executar um desafio.

Como exemplo, vamos imaginar o proprietário de uma pizzaria que criou um formulário de pedido on-line no React com uma página de pagamento que envia dados para um endpoint de API que processa pagamentos.  Quando um usuário visualiza o formulário da web para adicionar os detalhes do cartão de crédito, ele pode passar em um desafio gerenciado, mas quando o usuário envia os detalhes do cartão de crédito fazendo uma solicitação de busca, o navegador não executa o código necessário para a execução do desafio.  A única opção do proprietário da pizzaria para lidar com solicitações suspeitas (mas possivelmente legítimas) é bloqueá-las, o que gera risco de falsos positivos e pode fazer com que o restaurante perca uma venda.

É aqui que o Turnstile pode ajudar. O Turnstile permite que qualquer pessoa na internet incorpore um desafio da Cloudflare em qualquer lugar do seu site. Antes, a saída do Turnstile era apenas um token de uso único. Para permitir que os clientes emitam desafios para essas solicitações de busca, o Turnstile, agora, pode emitir um cookie de liberação para o domínio no qual está incorporado. Os clientes podem emitir seu desafio na página HTML antes de uma solicitação de busca, autorizando previamente o visitante para interagir com a API de pagamento.

Modo de pré-autorização do Turnstile

Voltando ao nosso exemplo da pizzaria, as três grandes vantagens de usar a Pré-autorização para integrar o Turnstile ao WAF da Cloudflare são:

  1. Experiência do usuário aprimorada: o desafio incorporado do Turnstile pode ser executado em segundo plano enquanto o visitante insere seus detalhes de pagamento.

  2. Bloqueio de mais solicitações na borda: como o Turnstile agora emite um cookie de autorização para o domínio no qual está incorporado, o proprietário da nossa pizzaria pode usar uma regra personalizada para emitir um desafio gerenciado para cada solicitação à API de pagamento. Isso garante que os ataques automatizados que tentam atingir diretamente a API de pagamento sejam interrompidos pela Cloudflare antes que possam chegar à API.

  3. (Opcional) Proteger a ação e o usuário: nenhuma alteração no código de back-end é necessária para obter o benefício da pré-autorização. No entanto, uma maior integração do Turnstile aumentará a segurança da API integrada. O proprietário da pizzaria pode ajustar sua forma de pagamento para validar o token Turnstile recebido, garantindo que cada tentativa de pagamento seja validada individualmente pelo Turnstile para proteger seu endpoint de pagamento contra sequestro de sessão.

Um widget do Turnstile com pré-autorização habilitada ainda emitirá tokens do Turnstile, o que dá aos clientes a flexibilidade de decidir se um endpoint é crítico o bastante para exigir uma verificação de segurança em cada solicitação ou apenas uma vez por sessão.  Os cookies de autorização emitidos por um widget do Turnstile são aplicados automaticamente à zona da Cloudflare na qual o widget do Turnstile está incorporado, sem necessidade de configuração.  O tempo de liberação para o qual o token é válido ainda é controlado pelo tempo de “passagem por desafios” específico da zona.

Implementar o Turnstile com pré-autorização

Vamos tornar isso concreto percorrendo uma implementação básica. Antes de começarmos, configuramos um aplicativo de demonstração simples onde emulamos um front-end conversando com um back-end em um endpoint /your-api.

Para isso, temos o seguinte código:

Criamos um botão. Ao clicar, a Cloudflare faz uma solicitação fetch() para o endpoint /your-api, mostrando o resultado no contêiner de resposta.

<!DOCTYPE html>
<html lang="en">
<head>
   <title>Turnstile Pre-Clearance Demo </title>
</head>
<body>
  <main class="pre-clearance-demo">
    <h2>Pre-clearance Demo</h2>
    <button id="fetchBtn">Fetch Data</button>
    <div id="response"></div>
</main>

<script>
  const button = document.getElementById('fetchBtn');
  const responseDiv = document.getElementById('response');
  button.addEventListener('click', async () => {
  try {
    let result = await fetch('/your-api');
    if (result.ok) {
      let data = await result.json();
      responseDiv.textContent = JSON.stringify(data);
    } else {
      responseDiv.textContent = 'Error fetching data';
    }
  } catch (error) {
    responseDiv.textContent = 'Network error';
  }
});
</script>

Agora vamos considerar que temos uma regra do Cloudflare WAF configurada que protege o endpoint /your-api com um desafio gerenciado.

Devido a esta regra, o aplicativo que acabamos de escrever irá falhar pelo motivo descrito anteriormente (o navegador espera uma resposta JSON, mas em vez disso recebe a página de desafio como HTML).

Se inspecionarmos a guia rede, podemos ver que a solicitação para /your-api recebeu uma resposta 403.

Após a inspeção, o cabeçalho Cf-Mitigated mostra que a resposta foi desafiada pelo firewall da Cloudflare, pois o visitante não resolveu um desafio antes.

Para resolver esse problema em nosso aplicativo, configuramos um widget do Turnstile no modo pré-autorização para a chave do site do Turnstile que queremos usar.

Em nossa aplicativo, substituímos a função fetch() para invocar o Turnstile assim que uma resposta Cf-Mitigated for recebida.

Há muita coisa acontecendo no trecho acima: Primeiro, criamos um elemento de sobreposição oculto e substituímos a função fetch()do navegador.  A função fetch()foi alterada para examinar o cabeçalho Cf-Mitigated para "desafio".  Se um desafio for lançado, o resultado inicial não será bem-sucedido. Em vez disso, uma sobreposição do Turnstile (com pré-autorização habilitada) aparecerá em nosso aplicativo web.  Assim que o desafio do Turnstile for concluído, tentaremos novamente a solicitação anterior depois que o Turnstile obtiver o cookie cf_clearance para passar pelo Cloudflare WAF.

<script>
turnstileLoad = function () {
  // Save a reference to the original fetch function
  const originalFetch = window.fetch;

  // A simple modal to contain Cloudflare Turnstile
  const overlay = document.createElement('div');
  overlay.style.position = 'fixed';
  overlay.style.top = '0';
  overlay.style.left = '0';
  overlay.style.right = '0';
  overlay.style.bottom = '0';
  overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
  overlay.style.border = '1px solid grey';
  overlay.style.zIndex = '10000';
  overlay.style.display = 'none';
  overlay.innerHTML =       '<p style="color: white; text-align: center; margin-top: 50vh;">One more step before you proceed...</p><div style=”display: flex; flex-wrap: nowrap; align-items: center; justify-content: center;” id="turnstile_widget"></div>';
  document.body.appendChild(overlay);

  // Override the native fetch function
  window.fetch = async function (...args) {
      let response = await originalFetch(...args);

      // If the original request was challenged...
      if (response.headers.has('cf-mitigated') && response.headers.get('cf-mitigated') === 'challenge') {
          // The request has been challenged...
          overlay.style.display = 'block';

          await new Promise((resolve, reject) => {
              turnstile.render('#turnstile_widget', {
                  'sitekey': ‘YOUR_TURNSTILE_SITEKEY',
                  'error-callback': function (e) {
                      overlay.style.display = 'none';
                      reject(e);
                  },
                  'callback': function (token, preClearanceObtained) {
                      if (preClearanceObtained) {
                          // The visitor successfully solved the challenge on the page. 
                          overlay.style.display = 'none';
                          resolve();
                      } else {
                          reject(new Error('Unable to obtain pre-clearance'));
                      }
                  },
              });
          });

          // Replay the original fetch request, this time it will have the cf_clearance Cookie
          response = await originalFetch(...args);
      }
      return response;
  };
};
</script>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=turnstileLoad" async defer></script>

Ao resolver o widget do Turnstile, a sobreposição desaparece e o resultado da API solicitada é mostrado com sucesso:

A pré-autorização está disponível para todos os clientes da Cloudflare

Todos os usuários da Cloudflare com plano gratuito ou superior podem usar o Turnstile no modo gerenciado gratuitamente para um número ilimitado de solicitações. Se você é um usuário da Cloudflare e deseja melhorar a segurança e a experiência do usuário para seus endpoints de API críticos, acesse nosso painel e crie um widget do Turnstile com pré-autorização hoje mesmo.

Protegemos redes corporativas inteiras, ajudamos os clientes a criarem aplicativos em escala de internet com eficiência, aceleramos qualquer site ou aplicativo de internet, evitamos os ataques de DDoS, mantemos os invasores afastados e podemos ajudar você em sua jornada rumo ao Zero Trust.

Acesse 1.1.1.1 a partir de qualquer dispositivo para começar a usar nosso aplicativo gratuito que torna sua internet mais rápida e mais segura.

Para saber mais sobre nossa missão de construir uma internet melhor, comece aqui. Se estiver procurando uma nova carreira para trilhar, confira nossas vagas disponíveis.
SegurançaCAPTCHABots (PT)TurnstileNotícias de produtosDesenvolvedoresMicro-frontends (PT)

Seguir no X

Adam Martinetti|@adamemcf
Benedikt Wolters|@worengawins
Miguel de Moura|@miguel_demoura
Cloudflare|@cloudflare

Posts relacionados