black box / aplicações web / newsletter

Do formulário à API

Um guia do básico ao avançado para analisar integrações de newsletter em sites sem CMS.

Uma integração de newsletter pode parecer apenas um formulário com um campo de e-mail. Por trás dele, porém, pode haver um endpoint próprio que usa uma credencial do servidor para cadastrar contatos em Mailchimp ou em outro provedor. O risco aparece quando o backend deixa o visitante escolher parâmetros que deveriam vir da configuração confiável do formulário.

Escopo deste guia: o caso analisado anteriormente era específico de uma integração WordPress. Aqui, o foco é o mesmo padrão de confiança indevida em aplicações sem WordPress: sites estáticos, frontends customizados e funções serverless. Isso descreve uma classe de falha possível, não uma vulnerabilidade presente em todo formulário.

1. O básico: navegador, servidor e provedor

O frontend é a página aberta no navegador. Ele mostra os campos e monta a requisição. O backend é a API ou função do site que recebe essa requisição. O provedor é o serviço externo que mantém a lista de contatos.

Quando o backend conversa com o provedor usando uma chave de API guardada no servidor, ele possui uma capacidade que o visitante não deveria controlar diretamente. O backend precisa decidir qual formulário está sendo enviado, a qual audiência ele pertence e quais regras de inscrição se aplicam.

Uma audiência é a lista ou grupo de contatos de destino. O double opt-in é um fluxo em que a pessoa recebe uma mensagem e precisa confirmar a inscrição. Consentimento, audiência e confirmação são decisões diferentes: a presença de um e-mail válido não prova, por si só, que seu titular pediu a inscrição.

2. O modelo de dados

No black box, trate cada valor enviado pelo navegador como entrada controlada pelo cliente. Um campo oculto continua editável; JavaScript também pode ser pausado ou modificado. Entre os valores comuns estão email, form_id, audience_id, tags e double_opt_in.

O dado de origem, ou source, é o valor que entra na aplicação. O sink é o ponto onde ele causa um efeito sensível, como uma chamada à API do provedor que cria ou atualiza um contato. Seguir esse caminho ajuda a separar uma mudança visual no navegador de uma mudança realmente aceita pelo servidor.

campos preenchidos no navegador ↓ requisição HTTP para a aplicação ↓ endpoint próprio ou função serverless ↓ validação e resolução da configuração do formulário ↓ chamada autenticada ao provedor de newsletter ↓ contato criado, atualizado ou deixado pendente

3. A teoria da falha: confiança indevida em parâmetros

Imagine que o backend recebe audience_id e double_opt_in do cliente. Se usa esses valores sem compará-los com uma configuração autorizada, o visitante pode tentar trocar a lista de destino ou alterar o fluxo de confirmação.

O problema não é o cliente conseguir editar a própria requisição — isso é esperado. O problema é o servidor tratar os valores alterados como decisões confiáveis. Uma validação de formato pode confirmar que um ID parece válido, mas não responde se aquele formulário tem permissão para usar essa audiência.

Também é importante separar autorização de proteção contra CSRF. Um token público ou nonce pode ajudar a reconhecer uma requisição originada pelo fluxo do site, mas não deve conceder ao visitante o direito de escolher a audiência nem de mudar a política de inscrição.

4. Onde procurar essa funcionalidade

Procure funções de cadastro em newsletter, assinatura de mailing list, captura de leads, inscrição em novidades ou formulários que sincronizam contatos com um CRM. A aplicação pode usar uma API em Node, PHP, Python, uma função serverless ou uma plataforma de automação.

Na aba Network do navegador, observe para onde o formulário envia os dados. Se a requisição vai para uma rota do próprio domínio, existe um backend a investigar. Se o formulário envia diretamente ao provedor, essa falha específica no backend do site pode não existir; ainda assim, não conclua nada apenas pela aparência do formulário.

5. Validação black box, passo a passo

Passo 1 — confirme o escopo e o ambiente. Use um ativo autorizado. Prefira staging, uma conta de teste ou um mock do provedor. Uma requisição válida pode alterar contatos reais.

Passo 2 — capture o fluxo normal. Envie um endereço controlado por você e guarde a rota, o método, os nomes dos parâmetros e a resposta. Redija tokens e dados pessoais ao salvar evidências.

Passo 3 — formule uma hipótese. Pergunte se o servidor decide a audiência a partir do ID do formulário ou se aceita uma audiência enviada pelo cliente. Faça uma alteração por vez.

Passo 4 — teste com dados próprios. Em staging, altere ou remova o identificador do formulário e, quando autorizado, envie a audiência de teste. Para consentimento, use apenas um contato controlado e uma configuração isolada.

Passo 5 — confirme no sink. Confira os logs do backend ou o estado do contato na audiência de teste. Uma resposta HTTP 200 não prova que o provedor aceitou a mudança, e uma mensagem de sucesso na interface não prova qual estado foi gravado.

Passo 6 — pare após a confirmação. Não use endereços de terceiros, não enumere IDs de audiências e não faça carga ou repetição em massa. Um único teste controlado costuma bastar para demonstrar o controle indevido.

6. PoC conceitual para laboratório

O formato real depende da requisição observada. Este exemplo representa um backend próprio e serve somente para um ambiente de teste. Não o envie a um domínio público sem autorização e sem entender o efeito da integração.

POST /api/subscribe
Content-Type: application/json

{
  "email": "ENDERECO_CONTROLADO_PELO_PESQUISADOR",
  "form_id": "formulario-de-teste",
  "audience_id": "audiencia-de-teste",
  "double_opt_in": false
}

O achado é confirmado se o backend usar sua credencial e realizar a inscrição com a audiência ou regra controlada pelo pedido, sem verificar se esses valores pertencem à configuração permitida para formulario-de-teste. Se o backend ignorar o campo, rejeitar a requisição ou resolver a configuração no servidor, essa hipótese não se confirma por esse teste.

7. Do intermediário ao avançado

Limite de confiança e invariantes

Escreva o que precisa permanecer verdadeiro: cada formulário usa uma audiência previamente definida; somente o servidor decide se a confirmação é necessária; o e-mail recebido não pode alterar esses controles. Depois, verifique se cada endpoint mantém essas invariantes, inclusive quando faltam campos ou quando um identificador é inválido.

Autorização por objeto e separação entre clientes

Em sistemas com várias marcas, clientes ou contas, um form_id pode selecionar configurações de outra organização. Verifique se o servidor associa o formulário ao tenant correto, em vez de aceitar um identificador de audiência arbitrário. Não tente acessar dados de outros clientes: valide apenas com recursos de teste autorizados.

Estado e transições

Modele estados como pending, subscribed e unsubscribed. A análise avançada pergunta quais transições o endpoint permite, quem pode solicitá-las e se uma atualização pode reativar um contato sem o fluxo esperado. A resposta do provedor e suas regras também fazem parte da validação.

Replay, abuso e integrações

Depois de validar a autorização, examine separadamente repetição de pedidos, limites de frequência, tratamento de falhas, duplicatas e webhooks de confirmação. Um limite por cliente pode reduzir abuso, mas não corrige a autorização incorreta sobre audiência ou consentimento. Não faça testes de volume sem autorização explícita.

Credenciais e fronteiras do provedor

Confirme que a chave de API não aparece no HTML, no bundle JavaScript ou na resposta ao navegador. Uma chave exposta é um achado diferente. Quando o backend mantém a chave, a evidência importante para este caso é mostrar que valores do cliente controlam uma chamada autenticada do servidor.

8. Falsos positivos comuns

Um campo editável não basta para provar impacto. O backend pode ignorá-lo; o provedor pode rejeitar a operação; ou o formulário pode enviar diretamente ao serviço sem um proxy do site. Uma lista visível no navegador também não prova que o usuário consegue gravar contatos nela. Confirme o efeito no sistema de destino de teste.

9. Impacto e severidade

Se confirmado, o impacto pode incluir inscrições indesejadas, alteração de contatos ou uso indevido da audiência configurada. O alcance depende das credenciais e permissões do backend, das audiências disponíveis e das regras do provedor. Não alegue acesso à chave, leitura de contatos ou comprometimento da conta se o teste não demonstrar isso.

Para um relatório de bounty, descreva as pré-condições, o parâmetro controlado, o estado observado no destino de teste e os limites da evidência. A classificação final deve seguir o impacto real e as regras do programa.

10. Como corrigir

Associe cada formulário a uma configuração fixa no servidor. Receba do cliente apenas um identificador opaco do formulário e os dados necessários do contato; resolva audiência, tags e política de confirmação no backend. Rejeite formulários desconhecidos, aplique autorização por tenant e mantenha a credencial do provedor fora do frontend.

A regra prática é simples: o navegador pode enviar uma intenção de inscrição; o servidor decide a operação permitida.

← voltar