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:

  1. o recurso ainda é necessário?
  2. pode ser hospedado no próprio pacote?
  3. a autorização pode ficar restrita a um hostname?
  4. quais dados saem da página?
  5. 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:

  1. localize atributos style e blocos <style>;
  2. mova estilos estáveis para a folha própria;
  3. identifique o que o framework injeta em runtime;
  4. teste hashes quando o conteúdo for fixo;
  5. 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-endpoint

O 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:

Terminal window
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:

Terminal window
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-src não substitui diretivas críticas;
  • object-src, base-uri e frame-ancestors definidos;
  • form-action representa 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.