Total Exibido Versus Total Enviado: Lendo um Formulário de Checkout

Fundamentos de Segurança Nível 3/4 ~4 min 10 de setembro de 2026

O desafio

Uma página de checkout mostra um resumo limpo e confiante: um plano, um preço, um total a pagar hoje. O número que o cliente lê e o número que o serviço de cobrança realmente cobra são calculados em dois lugares completamente diferentes, e nesta página eles divergiram. Olhe primeiro a página renderizada e anote o total anunciado, depois mude para o código-fonte e leia todos os campos que o formulário vai de fato enviar. Um comentário na marcação explica como o servidor soma a cobrança. Descubra quanto este formulário realmente cobra quando o cliente aperta Confirmar e pagar, e envie esse número.

O que você vai aprender

  • Comparar o que uma página renderiza com o que seu formulário realmente envia
  • Identificar campos de input ocultos e os valores que eles carregam
  • Aplicar uma regra de soma do lado do servidor, explicitamente informada, aos dados do formulário
  • Diferenciar campos com preço de campos de metadados em um formulário
  • Explicar por que preços nunca devem ser calculados a partir de valores enviados pelo cliente

Habilidades testadas

Inspeção de código-fonte HTMLAnálise de confiança no lado do clienteRevisão de fluxo de pagamento

Pré-requisitos

  • Leitura básica de marcação HTML de formulários
  • Entender que inputs ocultos também são enviados

Como funciona

Uma página de checkout é dois cálculos vestindo uma única interface. O template renderiza um total para um humano ler, e o formulário monta um conjunto de campos para um serviço de cobrança processar. Nada obriga esses dois números a coincidir, e quando eles se afastam a interface continua parecendo correta, porque a parte que o cliente consegue ver é a parte que nunca foi autoritativa.

A pré-visualização mostra uma única assinatura e Total due today: 290 EUR. Essa string vive no corpo da página. Não é um input, então nunca é enviada e o servidor nunca a vê.

O código-fonte mostra o que de fato vai acontecer. Um comentário enuncia a regra de cobrança sem rodeios: o serviço cobra plan_price mais cada campo addon_* mais promo_credit. Quatro campos batem com essa regra: plan_price em 290, addon_priority_support em 120, addon_onboarding em 450 e promo_credit em -60. Somando-os mantendo o sinal, o resultado é 800. Três outros campos ocultos, plan_id, currency e csrf, não carregam preço e ficam fora da regra.

Ou seja, a página anuncia 290 e o formulário cobra 800. Nenhum dos dois componentes está com defeito; eles simplesmente discordam, e essa discordância é invisível a partir da página renderizada. A mesma arquitetura falha a favor do cliente com a mesma facilidade, porque um formulário que carrega os próprios preços é um formulário que o cliente pode editar antes de enviar. Exibir um preço é uma questão de apresentação; decidir um preço é uma questão do servidor, e esta página confundiu as duas coisas.

Erros comuns

  • Responder 290. Essa é a string renderizada. Não é um campo de formulário e nunca é enviada.
  • Responder 860. Isso descarta o sinal de promo_credit, que é -60 e reduz a cobrança.
  • Responder 570. Isso soma o plano e apenas um addon, deixando de fora addon_onboarding. Os dois campos addon_* contam.
  • Incluir plan_id, currency ou csrf. Eles são ocultos, mas não carregam preço, e a regra enunciada não os cobre.
  • Parar na pré-visualização. Todo campo com preço nesta página está oculto, então a visualização renderizada sozinha não responde à pergunta.
  • Somar o IVA. O rodapé afirma que os preços já o incluem, e nenhum campo de imposto é enviado.

Como se proteger

A regra é simples e absoluta: o navegador pode exibir um preço, mas nunca pode fornecer um.

  • Envie identificadores, não valores. O formulário deve enviar plan_id e uma lista de ids de addons selecionados, e o servidor deve buscar cada preço no próprio catálogo.
  • Calcule o total no servidor e renderize o valor exibido a partir desse mesmo cálculo, para que um número nunca possa se afastar do outro.
  • Trate qualquer campo com preço vindo do cliente como entrada não confiável, e rejeite de vez uma requisição que carregue um, em vez de tentar validá-lo.
  • Amarre a cotação. Emita uma cotação ou id de carrinho do lado do servidor com o valor já anexado, e cobre com base nesse id.
  • Reconcilie continuamente, alertando quando o valor cobrado difere do valor cotado para o mesmo carrinho, o que pega essa classe de bug em produção.
  • Cubra isso em testes, garantindo que a cobrança gerada por um checkout seja igual ao total que a página exibiu.

Solução completa

Membros Pro e Max desbloqueiam o passo a passo completo.

Assinar Pro

Estatísticas da comunidade

172 resoluções
88% taxa de sucesso
Hodanalo Primeiro sangue

Hacks de hoje relacionados

25.000+ Hackers 100+ Labs & Cursos Grátis
Comece Grátis