DEV Community

Cover image for Content Security Policy (CSP) no NestJS: protegendo sua aplicação com Helmet
Bruno Mestres
Bruno Mestres

Posted on

Content Security Policy (CSP) no NestJS: protegendo sua aplicação com Helmet

Quando falamos sobre segurança em APIs, normalmente pensamos em autenticação, autorização e validação de dados.

Mas existe outra camada de proteção que muitas vezes passa despercebida: os headers de segurança HTTP.

Um deles é o Content Security Policy (CSP).

Neste tutorial, vamos entender o que é CSP e como configurá-lo em uma aplicação NestJS utilizando o Helmet.

O que é CSP?

O Content Security Policy é um mecanismo de segurança que permite definir quais recursos o navegador está autorizado a carregar e executar.

Por exemplo, podemos restringir:

  • Scripts JavaScript.
  • Arquivos CSS.
  • Imagens.
  • Recursos de domínios externos.

Isso ajuda a reduzir os riscos de ataques como Cross-Site Scripting (XSS), limitando a execução de conteúdos não autorizados.

Vale destacar que o CSP é uma camada adicional de proteção, não um substituto para validação de entradas e tratamento seguro de dados.

1. Instalando o Helmet

O NestJS permite utilizar o Helmet como middleware para configurar diversos headers de segurança.

Primeiro, instale a dependência:

npm install helmet
Enter fullscreen mode Exit fullscreen mode

Depois, importe o Helmet no arquivo main.ts:

import helmet from 'helmet';
Enter fullscreen mode Exit fullscreen mode

2. Configurando o CSP

Vamos adicionar a configuração ao bootstrap da aplicação.

import { NestFactory } from '@nestjs/core';
import helmet from 'helmet';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.use(
    helmet({
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          scriptSrc: ["'self'"],
          styleSrc: ["'self'", "'unsafe-inline'"],
          imgSrc: ["'self'", 'data:', 'https:'],
        },
      },
      crossOriginEmbedderPolicy: false,
      hsts: {
        maxAge: 31536000,
        includeSubDomains: true,
        preload: true,
      },
    }),
  );

  await app.listen(3000);
}

bootstrap();
Enter fullscreen mode Exit fullscreen mode

Com isso, o Helmet passa a enviar headers de segurança nas respostas HTTP da aplicação.

Importante: o CSP é aplicado pelo navegador aos documentos que ele carrega. Em uma API que retorna apenas JSON, seu efeito direto costuma ser limitado.

Ele se torna especialmente relevante quando o NestJS também entrega páginas HTML, documentação Swagger ou outros recursos consumidos pelo navegador.

3. Entendendo as diretivas

Vamos analisar as configurações que utilizamos.

defaultSrc: ["'self'"]

Define a política padrão para recursos que não possuem uma diretiva específica.

O valor 'self' permite carregar recursos da mesma origem da página.

scriptSrc: ["'self'"]

Restringe o carregamento de scripts à própria origem.

Isso ajuda a impedir a execução de scripts externos não autorizados.

styleSrc: ["'self'", "'unsafe-inline'"]

Permite carregar estilos da própria origem e utilizar estilos inline.

O unsafe-inline facilita a compatibilidade com aplicações que dependem desse comportamento, mas reduz a proteção oferecida pelo CSP.

Sempre que possível, prefira estilos externos ou mecanismos como nonces e hashes.

imgSrc: ["'self'", "data:", "https:"]

Permite carregar imagens de três tipos de origem:

  • 'self': mesma origem da aplicação.
  • data:: imagens incorporadas utilizando Data URLs.
  • https:: imagens provenientes de qualquer origem HTTPS.

Essa configuração oferece flexibilidade, mas pode ser restringida a domínios específicos quando necessário.

4. E as outras configurações do Helmet?

Além do CSP, adicionamos duas configurações importantes.

crossOriginEmbedderPolicy: false

Desativa o envio do header Cross-Origin-Embedder-Policy pelo Helmet.

Isso pode evitar problemas de compatibilidade com recursos externos que não estão preparados para as exigências dessa política.

Por outro lado, desativá-lo significa abrir mão dessa camada de isolamento.

hsts

hsts: {
  maxAge: 31536000,
  includeSubDomains: true,
  preload: true,
}
Enter fullscreen mode Exit fullscreen mode

O HTTP Strict Transport Security (HSTS) instrui navegadores a utilizar HTTPS para futuras conexões com o domínio.

Nessa configuração:

  • maxAge: mantém a política por aproximadamente um ano.
  • includeSubDomains: estende a política aos subdomínios.
  • preload: declara a intenção de utilizar a lista de pré-carregamento HSTS dos navegadores.

Atenção: configurar preload: true não adiciona automaticamente seu domínio à lista de preload.

Antes de utilizar essa opção em produção, é importante garantir que todos os subdomínios envolvidos suportem HTTPS corretamente.

5. Como verificar se está funcionando?

Inicie a aplicação:

npm run start:dev
Enter fullscreen mode Exit fullscreen mode

Depois, faça uma requisição para um endpoint existente:

curl -i http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

Você deverá encontrar um header semelhante a este:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:
Enter fullscreen mode Exit fullscreen mode

O Helmet também pode adicionar outras diretivas padrão à política, mesmo que não estejam explicitamente declaradas no código.

Outra opção é abrir o DevTools do navegador, acessar a aba Network e inspecionar os Response Headers.

Para verificar se uma política realmente bloqueia recursos, é necessário testá-la em uma página HTML que tente carregá-los.

6. Quais são os trade-offs?

Apesar dos benefícios, configurar CSP exige alguns cuidados.

Benefícios

  • Redução da superfície de ataque: ajuda a mitigar determinadas formas de XSS.
  • Controle de recursos: permite definir quais origens são autorizadas.
  • Segurança adicional: adiciona uma camada de proteção no navegador.
  • Centralização: facilita a configuração de headers de segurança.

Trade-offs

  • Compatibilidade: políticas restritivas podem bloquear recursos legítimos.
  • Estilos e scripts inline: algumas bibliotecas podem exigir ajustes.
  • Integrações externas: domínios utilizados pela aplicação precisam ser considerados.
  • Manutenção: novas dependências podem exigir alterações na política.

Uma boa estratégia é começar utilizando Content-Security-Policy-Report-Only para identificar possíveis violações antes de aplicar bloqueios em produção.

Conclusão

Implementar CSP com Helmet no NestJS é relativamente simples.

O maior desafio não está em adicionar o middleware, mas em definir uma política que equilibre segurança e compatibilidade.

Também é importante lembrar que o Helmet oferece outras proteções além do CSP, e que headers de segurança não substituem boas práticas de desenvolvimento.

Segurança não depende de uma única configuração. Ela é construída em camadas.

Top comments (0)