Pular para o conteúdo
Development

A troca de um token de uma linha que encontrou um botão quebrado e uma lacuna de GDPR

Por Victor Da Luz•
securityanalyticsdev-logsite

Isso parecia o menor ticket possível: o Cloudflare Web Analytics estava injetando automaticamente seu beacon de rastreamento no edge, contornando o próprio portão de consentimento deste site. Desligar o auto-inject no dashboard, trocar um token de placeholder por um de verdade em analytics.ts, pronto. Um clique no dashboard, uma troca de string.

Em vez disso virou a caçada de bug mais produtiva que tive neste site em semanas, e nenhum dos dois bugs que encontrei era o que eu tinha ido procurar.

O dashboard tinha mudado de lugar

Fui de memória, Analytics & Logs, um toggle, pronto. O dashboard de verdade não batia com nada disso. A Cloudflare tinha reorganizado a página de Web Analytics desde a última vez que eu tinha olhado. Em vez de chutar de novo, fui buscar a documentação atual de verdade e achei o caminho real: Manage RUM Settings → “Enable with JS Snippet installation.” Coisa pequena, mas é a diferença entre estar confiantemente errado e simplesmente confirmar o que é verdade antes de agir.

A troca do token em si estava correta. Verificar ela não estava.

A mudança de código foi mesmo de uma linha: string de placeholder fora, token real dentro, mais um atributo type: "module" para bater com o formato atual do snippet da Cloudflare (eles tinham trocado de defer para isso em algum momento também). O astro check rodou limpo. Normalmente é aí que eu daria por encerrado.

Mas essa é uma mudança relevante para segurança, um script ou dispara sem consentimento ou não dispara, então rodei um passo completo de browser-verify em vez de confiar só no type checker. Primeira tentativa, contra o npm run dev: uma violação de Content-Security-Policy, completamente sem relação com qualquer coisa que eu tinha tocado. Segunda tentativa, contra um build de produção de verdade (npm run build && npm run preview): uma violação de CSP diferente. Mesma categoria de erro, duas causas diferentes, nenhuma das duas minha.

A do servidor de desenvolvimento acabou sendo uma pista falsa, o Astro empacota scripts inline de um jeito diferente no modo dev do que num build de produção, então um hash de CSP calculado contra o output do dev nunca vai bater com o que de fato vai pro ar. Lição anotada: nunca confie numa checagem de CSP contra astro dev. Sempre faça o build e o preview primeiro.

A que não era pista falsa

A violação do build de produção não sumiu. Rastreei ela até o handler de clique inline do GamesSection.astro, o script que revela o iframe do jogo Planetary Pathways quando você clica em “Launch.” O hash dele está fixado no código em public/_headers, configurado uma vez lá quando os headers de segurança entraram pela primeira vez. Uma passada de i18n sem relação nesse mesmo componente, dois dias antes, tinha mudado o output compilado do script o suficiente para invalidar aquele hash. Nada pegou isso, nem o astro check, nem o build, nem nenhum teste. O único sintoma era um erro de CSP visível só no console e um botão que não fazia nada quando clicado.

Guardei minha mudança de analytics e refiz o build para ter certeza de que eu não estava imaginando uma conexão. Mesma violação, main sem modificação. Confirmado: o botão de lançamento do jogo estava silenciosamente morto em produção havia dois dias, e o único jeito de alguém notar seria abrindo o devtools na página certa na hora certa. Registrei como um bug separado em vez de embutir um fix num ticket sem relação, os dois problemas não têm nada a ver um com o outro, só aconteceu de compartilhar a mesma aba do navegador.

Uma pergunta que valia a pena fazer duas vezes

No meio do caminho, parei para fazer uma pergunta que eu vinha adiando: a biblioteca de consentimento trata alguma coisa específica de UE? Meu primeiro instinto foi checar lógica de detecção de geolocalização, não existe nenhuma, por design. A resposta da biblioteca para “específico de UE” é “não existe nada específico de UE, porque todo mundo recebe opt-in por padrão,” o que é uma barra mais alta do que a maioria dos banners de consentimento com gate por geolocalização consegue passar.

Mas essa não era a lacuna de verdade. O padrão de consentimento informado do GDPR espera que um visitante consiga ver o que é coletado e por quê, tipicamente por um link para a política de privacidade bem ali no prompt de consentimento. A config do prompt da biblioteca tem uma mensagem, um botão de aceitar, um botão de recusar, nenhum campo para um link sequer. E o imperfectsystems.com não tem uma política de privacidade do site inteiro para linkar mesmo que tivesse. O vdaluz.com tem uma, mas a própria config de consentimento dele também não linka para ela, então a lacuna não é exatamente sobre este site, está na biblioteca compartilhada da qual os dois sites dependem. Registrei como um follow-up separado em vez de tentar projetar e lançar um fix ali mesmo.

O que eu continuaria fazendo

Nada disso, a correção do dashboard, o botão quebrado, a lacuna de consentimento, teria aparecido num typecheck verde. Cada um deles precisou de um navegador de verdade, requisições de rede reais, e um build de produção de verdade em vez do servidor de desenvolvimento. O ticket de uma linha consumiu boa parte de uma sessão, mas a alternativa era entregar um “pronto” que deixava silenciosamente uma funcionalidade quebrada de dois dias no lugar e nunca perguntava se o prompt de privacidade era legalmente suficiente. Mais devagar, mas do tipo de devagar que vale a pena.

Leitura relacionada

Development

O bug atrás do bug

Um widget do GitHub quebrado levou a uma demo pausada, e no caminho apareceu um CSP fixado por hash invalidado por uma correção de acessibilidade de uma linha.

Ler: O bug atrás do bug

Você também pode achar útil

Proton

Proton Mail

E-mail criptografado de ponta a ponta, com arquitetura de acesso zero.

Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).

Saiba mais
Proton

Proton VPN

VPN comercial com filtragem NetShield e interruptor de desligamento automático.

Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).

Saiba mais
NordPass

NordPass

Gerenciador de senhas da equipe por trás da NordVPN, com um plano gratuito.

Como afiliado da NordPass, ganho com compras qualificadas.

Saiba mais