Content Security Policy e seu CMP: como fazer CSP e consentimento funcionarem juntos
Duas camadas de segurança que precisam concordar
Uma Content Security Policy (CSP) informa ao navegador de quais origens uma página pode carregar scripts, estilos, imagens, frames e requisições de rede. Uma plataforma de gerenciamento de consentimento faz o trabalho oposto: decide quais desses scripts podem ser executados com base na escolha do usuário. Quando as duas são configuradas separadamente, elas entram em conflito. O CMP não carrega porque a CSP o bloqueia, ou a CSP é afrouxada tanto para acomodar o CMP e as tags de anúncios que deixa de proteger qualquer coisa.
Este guia explica de quais diretivas de CSP um CMP normalmente precisa, como os nonces interagem com a injeção de scripts e como implantar mudanças sem quebrar seu banner.
O que um CMP geralmente precisa da CSP
Os requisitos exatos dependem do fornecedor, então parta sempre da documentação do seu próprio CMP. Em geral, verifique estas diretivas:
script-src— o domínio de onde o script do CMP é carregado, além de quaisquer arquivos de script adicionais que ele carregue.connect-src— os endpoints que o CMP chama comfetchou XHR, como os de configuração, lista de fornecedores, geolocalização e registro do consentimento.style-src— o domínio das folhas de estilo e, possivelmente, estilos inline se o CMP injetar um elemento<style>ou definir atributos de estilo.img-src— logotipos, ícones e quaisquer pixels sem rastreamento usados pelo CMP.font-src— se o banner carrega suas próprias fontes.frame-src— se o CMP usa iframes, por exemplo para compartilhar consentimento entre domínios.
Em sites com TCF, lembre-se de que o CMP também cria na página um frame localizador chamado __tcfapiLocator. Esse frame é criado sem origem remota, então normalmente não precisa de uma entrada em frame-src, mas vale confirmar isso nos testes.
O problema do stub inline
A maioria dos CMPs pede que você coloque um pequeno script inline — o stub — no head da página, para que outros scripts possam enfileirar chamadas antes de o CMP principal carregar. Uma CSP rígida bloqueia scripts inline, a menos que você os permita explicitamente. Você tem três opções:
- Um nonce. Gere um valor aleatório por resposta, adicione-o ao cabeçalho CSP como
'nonce-...'e à tag<script>do stub. É a opção mais flexível para páginas dinâmicas. - Um hash. Adicione a
script-srco hash SHA-256 do conteúdo exato do stub. Funciona bem em sites estáticos, mas qualquer alteração no stub, até um espaço em branco, o quebra. - Hospedar o stub por conta própria como um arquivo externo no seu domínio, coberto por
'self'. Exige cuidado para que ele carregue cedo o bastante.
Evite 'unsafe-inline' como atalho. Ele permite todos os scripts inline, o que elimina boa parte da proteção que a CSP oferece.
Nonces e scripts que o CMP injeta
Um CMP que bloqueia scripts até o consentimento costuma funcionar retendo-os e injetando-os depois. Com uma CSP baseada em nonce, esses scripts injetados também precisam ser permitidos. Há duas abordagens comuns:
- Propagação do nonce. O CMP lê o nonce da sua própria tag de script e o adiciona a cada script que injeta. Verifique se o seu CMP oferece suporte a isso.
'strict-dynamic'. Essa palavra-chave diz aos navegadores compatíveis para confiar em scripts carregados por um script já confiável. Simplifica a vida com gerenciadores de tags e CMPs que injetam scripts, mas também significa que qualquer script em que você confia pode carregar outros, então confie com cuidado.
Os gerenciadores de tags levantam a mesma questão. Se você carrega tags de anúncios e de analytics por meio de um gerenciador de tags, siga a documentação dele sobre nonces e garanta que o CMP e o gerenciador usem uma abordagem consistente.
As tags de anúncios dificultam a CSP
A publicidade programática carrega scripts e frames de muitos domínios, e a lista muda conforme os parceiros de demanda mudam. Os editores costumam fazer uma de duas escolhas:
- Uma CSP rígida nas páginas sem anúncios programáticos e uma política mais ampla onde os anúncios são exibidos.
- Uma política focada nas diretivas que continuam gerenciáveis, como
frame-ancestors,object-src 'none'ebase-uri, enquanto as origens de scripts permanecem mais amplas.
Seja como for, o CMP deve estar na lista de permissões de forma explícita, e não coberto apenas por um curinga, para que uma mudança na CSP nunca desative o banner em silêncio.
Implante com o modo report-only
Use primeiro o cabeçalho Content-Security-Policy-Report-Only. O navegador relata as violações sem bloquear nada, então você pode ver o que uma nova política quebraria.
- Implante a política em modo report-only com um endpoint de relatórios.
- Carregue páginas em perfis de navegador limpos e percorra o fluxo de consentimento completo: primeira visita, aceitar tudo, rejeitar tudo, escolha personalizada, retirada.
- Revise os relatórios de violação e o console do navegador em busca de recursos do CMP bloqueados.
- Ajuste a política e depois passe para a aplicação efetiva.
- Mantenha os relatórios ativados após a aplicação para detectar regressões.
Sintomas de um conflito com a CSP
- O banner nunca aparece, e o console mostra uma violação de CSP para o script do CMP.
- O banner aparece, mas sem estilo, porque
style-srcbloqueia seu CSS. - As escolhas não são salvas, porque
connect-srcbloqueia a chamada de registro do consentimento. - Os anúncios ou o analytics nunca carregam após o consentimento, porque os scripts injetados não têm nonce.
__tcfapiestá indefinido, porque o stub inline foi bloqueado.
Principais conclusões
- Verifique
script-src,connect-src,style-src,img-srceframe-srcpara o seu CMP. - Permita o stub inline com um nonce ou um hash, não com
'unsafe-inline'. - Garanta que os scripts injetados após o consentimento recebam um nonce ou estejam cobertos por
'strict-dynamic'. - Teste cada caminho de consentimento em modo report-only antes de aplicar a política.
- Mantenha o CMP explicitamente na lista de permissões para que mudanças na CSP não possam desativá-lo.