Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Content Security Policy no Node.js

Atualizado em: 5 de outubro de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

Content Security Policy, ou CSP, é um cabeçalho HTTP que define quais fontes de scripts, estilos, imagens, fontes, frames e conexões podem ser usadas por uma página. Em aplicações Node.js, a CSP reduz o impacto de XSS e carregamento de recursos não autorizados.

Uma política eficiente não é apenas copiar default-src 'self'. É preciso mapear os recursos reais, eliminar scripts inline, usar nonce ou hash, testar em modo report-only e monitorar violações.

Política básica

import helmet from 'helmet';

app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'"],
    styleSrc: ["'self'"],
    imgSrc: ["'self'", 'data:', 'https:'],
    fontSrc: ["'self'"],
    connectSrc: ["'self'"],
    objectSrc: ["'none'"],
    baseUri: ["'self'"],
    formAction: ["'self'"],
    frameAncestors: ["'none'"],
  },
}));

default-src funciona como fallback. Diretivas específicas substituem o fallback para aquele tipo de recurso.

Nonce para scripts

import crypto from 'node:crypto';

app.use((req, res, next) => {
  res.locals.nonce = crypto.randomBytes(16).toString('base64');
  next();
});

app.use(helmet.contentSecurityPolicy({
  directives: {
    scriptSrc: [
      "'self'",
      (req, res) => `'nonce-${res.locals.nonce}'`,
    ],
  },
}));

No HTML:

<script nonce="{{nonce}}" src="/assets/app.js"></script>

O nonce deve ser imprevisível, exclusivo por resposta e aplicado somente a scripts confiáveis.

Hashes

Para um script inline estático, gere um hash SHA-256 e inclua:

script-src 'self' 'sha256-BASE64_DO_HASH'

Qualquer mudança no conteúdo exige atualizar o hash. Hashes são úteis para trechos pequenos e imutáveis.

Evite unsafe-inline

'unsafe-inline' permite execução de scripts inline e enfraquece a proteção contra XSS. Remova handlers como onclick do HTML e registre eventos no JavaScript externo.

Evite unsafe-eval

'unsafe-eval' permite eval, new Function e padrões semelhantes. Algumas ferramentas de desenvolvimento dependem disso, mas produção deve evitar. Use builds que não exigem eval.

strict-dynamic

'strict-dynamic' permite que um script autorizado por nonce carregue outros scripts. É poderoso, mas exige entendimento de compatibilidade e cadeia de confiança.

connect-src

Controla Fetch, XMLHttpRequest, WebSocket e EventSource:

connectSrc: [
  "'self'",
  'https://api.example.com',
  'wss://realtime.example.com',
]

Inclua somente destinos necessários. Em desenvolvimento, adicione hosts locais em configuração separada.

img-src

Imagens externas, data URLs e blobs precisam ser declarados. Permitir https: aceita qualquer domínio HTTPS; prefira hosts específicos quando possível.

frame-ancestors

Controla quem pode incorporar a página em iframe e reduz clickjacking:

frameAncestors: ["'self'", 'https://portal.example.com']

É mais flexível que X-Frame-Options para múltiplas origens.

frame-src e child-src

Controlam quais frames a página pode carregar. Não confunda com frame-ancestors, que controla quem pode carregar a sua página.

form-action

Limita destinos de formulários. Isso reduz exfiltração causada por HTML injetado:

formAction: ["'self'", 'https://payments.example.com']

base-uri

Um elemento <base> injetado pode alterar URLs relativas. Restrinja com base-uri 'self' ou 'none'.

object-src

Plugins legados raramente são necessários. Use:

objectSrc: ["'none'"]

upgrade-insecure-requests

Instrui o navegador a transformar recursos HTTP em HTTPS. Em desenvolvimento local pode causar problemas; ajuste apenas nesse ambiente.

block-all-mixed-content

Navegadores modernos já bloqueiam vários conteúdos mistos. A política reforça que recursos HTTP não devem ser carregados em páginas HTTPS.

Report-Only

Implante inicialmente sem bloquear:

app.use(helmet.contentSecurityPolicy({
  reportOnly: true,
  directives: policy,
}));

Analise violações e corrija recursos legítimos antes de ativar enforcement.

Endpoint de relatórios

app.post('/internal/csp-report',
  express.json({ type: ['application/csp-report', 'application/reports+json'], limit: '32kb' }),
  (req, res) => {
    logger.warn({ report: sanitizeReport(req.body) }, 'Violação CSP');
    res.sendStatus(204);
  },
);

Relatórios são dados não confiáveis. Limite tamanho, aplique rate limiting, sanitize URLs e não registre tokens.

report-uri e report-to

report-uri é amplamente conhecido, enquanto Reporting API usa report-to ou Reporting-Endpoints. Avalie suporte dos navegadores e mantenha compatibilidade durante migração.

Templates server-side

Garanta que o nonce chega ao layout e não é inserido em conteúdo controlado pelo usuário. Um atacante que obtém o nonce por injeção no mesmo documento pode contornar a política.

SPAs

SPAs frequentemente precisam de API, analytics, fontes e CDN. Liste cada origem e evite liberar esquemas inteiros. Ferramentas de build devem produzir arquivos externos com hashes de conteúdo.

Next.js, Vite e bundlers

Frameworks podem inserir scripts inline de hidratação. Consulte a integração específica e use nonce suportado oficialmente. Não adicione unsafe-inline apenas para silenciar erros.

CDN

Ao carregar bibliotecas de CDN, fixe domínio e considere Subresource Integrity:

<script
  src="https://cdn.example.com/lib.min.js"
  integrity="sha384-HASH"
  crossorigin="anonymous"></script>

SRI verifica o conteúdo, enquanto CSP controla a origem. As duas proteções se complementam.

Inline styles

Estilos inline também podem exigir nonce ou hash. Migrar para arquivos CSS ou classes reduz a necessidade de permissões amplas.

data e blob

Permitir data: ou blob: deve ser específico por diretiva. Não adicione globalmente. Blobs podem ser necessários para workers, downloads ou previews.

Web Workers

Configure worker-src:

workerSrc: ["'self'", 'blob:']

Remova blob se a aplicação não precisar.

Testes automatizados

const response = await request(app).get('/');
const csp = response.headers['content-security-policy'];

expect(csp).toContain("default-src 'self'");
expect(csp).toContain("object-src 'none'");
expect(csp).not.toContain("'unsafe-eval'");

Testes end-to-end devem abrir páginas e observar console, rede, login, pagamentos e recursos externos.

Observabilidade

Agrupe violações por diretiva, origem, release e página. Um pico após deploy pode indicar recurso legítimo bloqueado; origens estranhas podem revelar extensão, injeção ou ataque.

Segurança e privacidade

Relatórios podem conter URL da página, URL bloqueada e trechos. Remova query strings e dados pessoais antes de armazenar.

Erros comuns

  • usar unsafe-inline em toda a aplicação;
  • permitir qualquer domínio HTTPS;
  • reutilizar nonce;
  • não testar report-only;
  • confundir frame-src e frame-ancestors;
  • registrar relatórios sem sanitização;
  • ignorar WebSocket e EventSource em connect-src;
  • desativar CSP para corrigir uma integração;
  • não revisar a política após remover serviços.

Fluxo recomendado

  1. inventarie recursos;
  2. comece com default-src self;
  3. adicione diretivas mínimas;
  4. remova scripts inline;
  5. use nonce ou hash;
  6. ative report-only;
  7. corrija violações;
  8. ative bloqueio;
  9. monitore por release;
  10. revise periodicamente.

Combine CSP com Helmet no Node.js, CORS, TLS e HTTPS e logs com Pino.

Consulte a documentação de CSP da MDN e o guia de CSP da OWASP.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita