Uma landing page criada por IA costuma combinar código próprio, fontes externas, pixels, Analytics, formulário, vídeo e scripts copiados de exemplos. Se a Content Security Policy for permissiva demais, ela quase não reduz risco. Se for restritiva sem inventário, pode derrubar justamente a jornada de conversão.
Criar uma CSP é declarar quais recursos a página está autorizada a carregar e para onde pode enviar dados. A política deve refletir a versão real do site, não uma lista genérica de domínios acumulada até o console parar de reclamar.
Este guia mostra um fluxo gradual para páginas estáticas: inventariar, reduzir, testar em report-only, aplicar e verificar a URL publicada.
O que a CSP faz
O cabeçalho Content-Security-Policy permite controlar fontes de scripts, estilos, imagens, fontes, frames, conexões e outros recursos. A documentação do MDN sobre CSP explica que a política ajuda a reduzir ataques de injeção de conteúdo, especialmente cross-site scripting.
CSP é defesa em profundidade. Ela não corrige HTML inseguro, não valida dados no backend e não torna confiável um script de terceiro. Também não protege uma chave que já foi enviada ao navegador.
Use a CSP junto com a revisão de cabeçalhos de segurança e com o inventário de scripts de terceiros da landing page.
Modele a página antes da política
Comece com a build que será publicada. Abra a página, percorra as jornadas críticas e registre cada origem usada:
documento HTML:scripts próprios:scripts inline:estilos próprios:estilos inline:imagens e data URLs:fontes:fetch, beacon e WebSocket:destino de formulários:iframes:manifest e workers:Analytics e pixels:Use a aba Network e o código compilado. Não autorize um domínio só porque ele aparece em um arquivo de configuração antigo. Não esqueça recursos carregados apenas depois de aceitar cookies, enviar o formulário ou abrir um vídeo.
Para cada origem externa, pergunte:
- o recurso ainda é necessário?
- pode ser hospedado no próprio pacote?
- a autorização pode ficar restrita a um hostname?
- quais dados saem da página?
- quem aprova e mantém essa dependência?
Remover uma integração abandonada é melhor que criar uma exceção permanente.
Entenda as diretivas essenciais
Uma política é composta por diretivas. Estas costumam ser relevantes para uma landing page:
| Diretiva | Controla |
|---|---|
default-src |
fallback para tipos sem diretiva específica |
script-src |
JavaScript permitido |
style-src |
folhas de estilo e estilos permitidos |
img-src |
imagens e favicons |
font-src |
arquivos de fonte |
connect-src |
fetch, XHR, beacon e WebSocket |
frame-src |
conteúdo que a página incorpora |
frame-ancestors |
quem pode incorporar a página |
form-action |
destinos autorizados para formulários |
object-src |
plugins e objetos incorporados |
base-uri |
URLs permitidas para a tag <base> |
default-src 'self' é um fallback útil, mas não encerra o trabalho. Formulários, ancestrais de frame e outras capacidades precisam de diretivas próprias.
Comece com uma base pequena
Uma landing totalmente estática, com CSS e JavaScript externos hospedados no mesmo domínio, pode partir desta política:
default-src 'self';base-uri 'none';object-src 'none';frame-ancestors 'none';form-action 'self';img-src 'self' data:;font-src 'self';style-src 'self';script-src 'self';connect-src 'self';Leia isso como hipótese, não como receita. Se o formulário envia para um serviço externo, form-action 'self' vai bloqueá-lo. Se Analytics envia eventos para outra origem, connect-src 'self' não é suficiente. Se a página usa vídeo incorporado, frame-src precisa representar esse requisito.
Adicione apenas as origens confirmadas, na diretiva correta:
form-action 'self' https://forms.exemplo.com;connect-src 'self' https://analytics.exemplo.com;frame-src https://video.exemplo.com;Autorizar https: inteiro ou usar * elimina grande parte da precisão que a política deveria oferecer.
Trate scripts inline conscientemente
Geradores de site podem produzir <script> inline para menu, tema ou hidratação. A saída fácil é adicionar 'unsafe-inline' a script-src, mas isso também permite outros scripts inline e enfraquece a proteção contra injeção.
Para uma página estática, prefira:
- mover o script para um arquivo próprio e permitir
'self'; - usar um hash CSP para um bloco inline fixo;
- eliminar código inline que não é mais necessário.
Um hash precisa corresponder exatamente ao conteúdo do bloco. Qualquer mudança exige recalculá-lo e atualizar a política.
Nonces são adequados quando o servidor gera um valor imprevisível por resposta e o aplica ao header e aos elementos autorizados. Um valor fixo em um site estático não oferece essa propriedade. A orientação do web.dev sobre CSP estrita diferencia políticas baseadas em nonce e hash.
Não use 'unsafe-eval' para silenciar uma biblioteca sem investigar. Descubra quem exige avaliação dinâmica e se existe build ou alternativa compatível.
Faça o mesmo com estilos inline
style-src 'unsafe-inline' é comum em templates e ferramentas de terceiros, mas deve ser uma decisão visível. Antes de aceitar:
- localize atributos
stylee blocos<style>; - mova estilos estáveis para a folha própria;
- identifique o que o framework injeta em runtime;
- teste hashes quando o conteúdo for fixo;
- documente qualquer exceção restante.
Não copie uma solução de scripts para estilos sem confirmar suporte e comportamento. Cada diretiva tem regras próprias.
Use report-only antes de bloquear produção
O modo report-only observa violações sem aplicar o bloqueio:
Reporting-Endpoints: csp-endpoint="https://reports.exemplo.com/csp"Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'none'; report-uri https://reports.exemplo.com/csp; report-to csp-endpointO guia do MDN explica que Content-Security-Policy-Report-Only gera violações sem impor a política. Uma política report-only não pode ser entregue por <meta>; use o header HTTP.
O endpoint acima é ilustrativo: ele precisa existir, aceitar os formatos enviados pelos navegadores e receber aprovação antes do uso. O report-to referencia o nome declarado em Reporting-Endpoints; report-uri amplia a compatibilidade enquanto o mecanismo mais novo não estiver disponível em todos os navegadores. O console continua útil durante testes controlados, mas não substitui a coleta quando o objetivo é observar violações fora daquela sessão. Trate os relatórios como dados potencialmente sensíveis.
Teste pelo menos:
- carregamento inicial e navegação;
- menu mobile;
- envio válido e inválido do formulário;
- Analytics e consentimento;
- vídeo, mapa ou agenda incorporada;
- imagens responsivas e fontes;
- compartilhamento e parâmetros de campanha;
- página 404 e rotas internas.
Extensões do navegador podem gerar ruído. Reproduza em um perfil limpo antes de autorizar uma origem desconhecida.
Configure a política na camada que controla a resposta
O contrato atual de Publicação do Site no Ar não interpreta _headers dentro do pacote. Para entregar Content-Security-Policy-Report-Only, Reporting-Endpoints e depois Content-Security-Policy, confirme uma camada autorizada que consiga alterar a resposta HTTP, como um proxy ou origem administrada pela equipe, ou suporte explícito da plataforma.
Se essa camada ainda não existe, mantenha a política proposta e o inventário como pendência verificável. Não trate um arquivo _headers copiado para dist como proteção ativa. Uma CSP em <meta> pode aplicar parte das diretivas de enforcement, mas não oferece report-only e não suporta todos os controles, como frame-ancestors.
Quando houver suporte, inspecione os headers da URL publicada:
curl -sSI https://www.exemplo.com/ | rg -i 'content-security-policy|reporting-endpoints'Verifique a resposta real em cada hostname relevante; a presença da política apenas na fonte ou na build não prova que o navegador a recebeu.
Valide a política como comportamento
Durante report-only, classifique cada violação:
| Classe | Ação |
|---|---|
| recurso legítimo e aprovado | autorizar na diretiva mínima |
| recurso legítimo que pode ser local | mover para o próprio pacote |
| integração abandonada | remover da página |
| extensão do navegador | reproduzir em perfil limpo |
| origem desconhecida | investigar, não autorizar |
| script injetado | tratar como incidente ou defeito |
Depois que as jornadas passarem e as violações legítimas estiverem explicadas, troque para enforcement:
Content-Security-Policy: [política validada]Você pode manter uma segunda política report-only para testar a próxima versão. Se os dois headers estiverem presentes, a política principal continua sendo aplicada e a report-only apenas observa sua própria proposta.
Publique e confirme o header servido
Siga o contrato de Publicação para enviar a build e configure a política na camada HTTP confirmada. Depois, inspecione a resposta:
curl -sS -D - -o /dev/null https://exemplo.sitenoar.app/Confirme:
- apenas o header esperado está em enforcement;
- a política não foi truncada;
- não há valores duplicados combinados;
- a URL com domínio próprio recebe a política;
- formulários e integrações concluem a jornada;
- o console não mostra bloqueios inesperados;
- scripts rejeitados realmente ficam impedidos de executar.
Teste uma rota interna e uma página de erro. A camada de resposta pode aplicar políticas diferentes por hostname ou caminho; a home sozinha não prova cobertura.
Não confunda ausência de erro com proteção
Uma CSP como esta raramente é uma boa conclusão:
default-src * data: blob: 'unsafe-inline' 'unsafe-eval';Ela pode deixar o console silencioso justamente por autorizar quase tudo. Avalie a precisão das origens e a força de script-src, não apenas a ausência de violações.
Também evite declarar sucesso só porque um scanner reconheceu o header. A evidência precisa incluir jornadas, console, Network, resposta HTTP e versão publicada.
Evolua a política junto com a landing page
Cada novo pixel, widget, fonte ou formulário altera o mapa de recursos. Inclua a CSP na revisão de mudança:
integração adicionada:origens novas:diretivas alteradas:dados enviados:jornadas testadas:modo report-only iniciado em:enforcement aprovado por:versão publicada:Quando o conteúdo mudar, republique o mesmo Site para preservar URL e domínio. Se um hash de script inline mudou, atualize a política no mesmo commit da alteração do script.
Prompt copiável para o agente
Crie uma proposta de Content Security Policy para esta landing page sem publicar ainda.
Fonte: [caminho]Pasta publicável: [pasta]URL de teste: [URL]Jornadas críticas: [lista]Integrações aprovadas: [lista]
Primeiro inventarie, na build e no navegador:- scripts e estilos próprios ou inline;- imagens, fontes, conexões, formulários e frames;- todas as origens externas e sua finalidade.
Depois entregue:- política mínima em report-only;- alterações necessárias no código para evitar unsafe-inline e unsafe-eval;- matriz de testes;- violações encontradas e classificação;- política de enforcement proposta.
Não autorize wildcard para silenciar erro.Não use nonce fixo em site estático.Não publique nem ative enforcement sem aprovação.Checklist final
- build e jornadas inventariadas;
- integrações abandonadas removidas;
- cada origem está na diretiva correta;
-
default-srcnão substitui diretivas críticas; -
object-src,base-urieframe-ancestorsdefinidos; -
form-actionrepresenta o destino real; - scripts inline foram removidos, hasheados ou justificados;
- nenhum nonce fixo foi usado;
- report-only foi testado em perfil limpo;
- violações desconhecidas foram investigadas;
- camada responsável pelos headers foi confirmada;
- enforcement passou nas jornadas críticas;
- header publicado foi inspecionado;
- política e versão ficaram registradas.
Uma CSP forte nasce de uma lista curta de recursos conhecidos, não de exceções acumuladas. Quando a política acompanha a página, o deploy e os testes, ela reduz espaço para conteúdo inesperado sem transformar segurança em uma causa invisível de conversões quebradas.
