Skip to main content
Bastidores
BastidoresSecurityPremium

O que uma auditoria do nosso próprio sistema de pagamento revelou

Duas descobertas críticas, e nenhuma estava onde teríamos procurado. Um relato aberto sobre erros que já foram corrigidos.

Publicado em por AlphaCloud5 min de leitura

Em agosto de 2026 revisamos nosso sistema de pagamento do zero. Não porque algo tivesse acontecido, mas porque ele tinha entrado no ar pouco antes e queríamos saber o que tínhamos deixado passar.

Tínhamos deixado passar bastante coisa. Este artigo nomeia as descobertas. Tudo o que está descrito aqui foi corrigido, e a maior parte já estava no changelog público de qualquer forma.

O erro de modelagem de onde vieram as duas descobertas críticas

Quando alguém compra Premium conosco, um cadastro de cliente é criado no nosso provedor de pagamento. Armazenamos esse cadastro pelo ID do servidor, afinal o Premium vai para um servidor.

Esse é exatamente o modelo errado, e foi a raiz das duas descobertas mais graves.

Um cadastro de cliente pertence a um comprador. Ele carrega o método de pagamento, o histórico de faturas e, assim que alguém paga por dois servidores, várias assinaturas. Indexá-lo pelo ID do servidor significa que várias pessoas apontam para a mesma linha.

Descoberta 1: dados de cliente de outra pessoa, sobrescrevíveis sem pagar

A compra está aberta a qualquer membro de um servidor, e a função que busca ou cria o cadastro de cliente roda antes do pagamento. Ela encontrava a linha pelo ID do servidor e a reescrevia em silêncio para o novo interessado, incluindo o endereço de e-mail dele no provedor de pagamento.

Na prática, isso significava: bastava um clique num servidor em que alguém tinha comprado em algum momento. Depois disso, as faturas de todas as assinaturas daquele comprador original teriam ido para o endereço de e-mail do estranho. Sem pagamento, sem confirmação.

Corrigido verificando, antes de qualquer reaproveitamento, se o cadastro realmente pertence a esta conta. Se não pertencer, um cadastro separado é criado e o outro fica intocado.

Descoberta 2: o portal de cobrança expunha assinaturas de outras pessoas

O mesmo erro de modelagem, um nível adiante. A verificação de propriedade valia para a assinatura do servidor, mas a sessão do portal era aberta para o cadastro de cliente, que por design pode carregar vários servidores.

Assim, qualquer pessoa que comprasse legitimamente em um servidor podia ver e gerenciar as assinaturas que o mesmo cadastro carregava para outros servidores.

Corrigido resolvendo o cadastro de cliente a partir da compra específica, e não da linha do servidor.

Duas descobertas em que o código contradizia nossos próprios termos

Esta é a categoria que mais nos incomodou, porque não é técnica.

A lista negra tirava tempo já pago. Nossos termos dizem que uma assinatura termina no fim do período atual. Mas, ao bloquear um servidor, o código pedia o cancelamento imediato: sem reembolso e, a partir daquele momento, sem serviço por um período já pago. O código fazia algo diferente do que tínhamos prometido por escrito. Agora o período pago vai até o fim.

A renúncia ao direito de arrependimento não era comprovável. Antes de uma compra, você precisa confirmar que o serviço começa imediatamente. Essa confirmação existia só no navegador, nunca era enviada e nunca era armazenada em lugar nenhum. O ônus da prova é nosso, e simplesmente não tínhamos prova. Agora o consentimento é um campo obrigatório da rota de checkout, armazenado com data e hora e com um texto versionado, e o próprio texto é versionado: um texto existente nunca é editado, sempre se cria uma nova versão, senão os registros antigos não seriam mais reproduzíveis.

A segunda rodada foi pior que a primeira

Depois das primeiras 21 descobertas, olhamos de novo algumas semanas depois. Foi a decisão certa, porque a descoberta mais grave de todas só apareceu ali.

Um reembolso no servidor B apagava a licença vitalícia paga do servidor A. Notificações de reembolso e de chargeback citam só um pagamento, não um servidor. Nós as resolvíamos pelo cadastro de cliente. Como na primeira rodada tínhamos estabelecido corretamente que um cadastro pertence a um comprador em vários servidores, essa mesma resolução deixou de ser inequívoca. Alguém que tinha pago por dois servidores e recebido um reembolso por um deles podia perder a licença vitalícia do outro.

A resolução agora passa por quatro etapas exatas, e tudo o que não puder ser resolvido de forma inequívoca é reportado em vez de adivinhado.

Um chargeback ganho não restaurava nada. Num chargeback, o código apagava a linha da compra, a única prova de que aquele servidor algum dia teve uma licença vitalícia. Ganhar a disputa depois não podia desfazer isso. Agora ele marca em vez de apagar.

A retenção de dados apagava servidores pagos. Quando o bot sai de um servidor, os dados dele são removidos após 30 dias. Essa limpeza nunca perguntava se havia uma assinatura ativa vinculada.

O que levamos disso

Os bugs não estavam no código de pagamento. Nenhuma descoberta crítica dizia respeito a um valor, uma moeda ou um cálculo. Todas estavam no modelo por trás: quem é dono de um cadastro de cliente, quem é dono de um pagamento, quem é dono de um servidor. Quem audita um sistema de pagamento olhando para os valores está olhando para longe da parte perigosa.

Uma auditoria precisa de uma segunda rodada. A descoberta mais grave foi consequência direta de uma correção da primeira. Não é coincidência: corrigir um modelo invalida suposições que ainda valem em outros lugares.

"Nossos termos dizem isso" é uma frase verificável. Duas descobertas eram divergências entre o que tínhamos prometido por escrito e o que o código fazia. Isso pode ser lido, e ninguém lê, porque parece direito e não engenharia.

As condições de compra completas estão nos nossos termos de serviço, e o direito de arrependimento em arrependimento.

Mais artigos