Checklist de segurança para aplicações Backend com NestJS
Um checklist prático com 30 verificações de segurança para aplicações backend construídas com NestJS, cobrindo autenticação, autorização, validação de dados, rate limiting, secrets, CORS, CSRF, uploads, logs, dependências e infraestrutura.

Construir uma API com NestJS é relativamente simples. Construir uma API que continue segura quando estiver exposta à internet, recebendo dados não confiáveis e lidando com autenticação, arquivos, integrações externas e informações sensíveis exige uma camada adicional de cuidado.
O NestJS fornece diversos mecanismos para implementar segurança, como Guards, Pipes, interceptors, autenticação, autorização, rate limiting e headers de segurança. Mas o framework não consegue decidir quais regras de negócio devem ser protegidas em cada aplicação.
Este checklist reúne verificações que podem ser utilizadas antes de colocar uma aplicação NestJS em produção.
1. Autenticação está implementada corretamente?
Toda aplicação que possui usuários ou dados privados precisa definir claramente como a identidade do cliente será validada.
Verifique:
- Os endpoints privados exigem autenticação.
- Tokens inválidos são rejeitados.
- Tokens expirados são rejeitados.
- O algoritmo utilizado para validar JWT é explicitamente configurado.
- A aplicação não aceita tokens com algoritmos inesperados.
- Chaves e secrets não estão dentro do código-fonte.
- O mecanismo de refresh token possui proteção contra reutilização indevida.
- Tokens têm tempo de expiração adequado ao nível de risco da aplicação.
O NestJS documenta a utilização de Guards para proteger rotas e também permite registrar um Guard de autenticação global, deixando explicitamente marcadas apenas as rotas públicas. Essa abordagem reduz o risco de criar acidentalmente um endpoint privado sem proteção.
Uma estratégia interessante é adotar o princípio:
Por padrão, a rota é privada. A exceção precisa ser declarada explicitamente.
2. Autenticação não é autorização
Um usuário autenticado não significa que ele pode acessar qualquer recurso.
Considere uma API:
GET /users/123/ordersO fato de o usuário estar autenticado não significa que ele possa consultar os pedidos do usuário 123.
Esse tipo de problema está diretamente relacionado ao Broken Object Level Authorization (BOLA), listado como API1 no OWASP API Security Top 10.
Verifique:
- Cada recurso verifica quem pode acessá-lo.
- IDs enviados pelo cliente não são considerados autorização.
- Um usuário não consegue acessar objetos de outro usuário alterando um ID.
- Operações administrativas possuem autorização adicional.
- Alterar, excluir ou exportar dados exige as permissões apropriadas.
No NestJS, Guards podem ser utilizados para estruturar mecanismos como RBAC, mas a autorização de cada recurso ainda precisa refletir as regras reais da aplicação.
3. Evite confiar em dados enviados pelo cliente
Nunca considere seguro algo simplesmente porque existe um DTO ou porque o TypeScript declarou um tipo.
O cliente controla a requisição.
Ele pode enviar:
{
"name": "Fernando",
"role": "admin",
"isActive": true,
"balance": 999999
}Se a aplicação simplesmente persistir tudo que recebeu, o problema pode virar uma vulnerabilidade de mass assignment ou de autorização em nível de propriedade.
A API deve definir explicitamente quais campos podem ser recebidos em cada operação.
Por isso, prefira DTOs específicos:
export class CreateUserDto {
name: string;
email: string;
}Em vez de reutilizar diretamente uma entidade de banco de dados como entrada da API.
4. Use ValidationPipe globalmente
A validação dos dados recebidos deve acontecer antes que eles cheguem à lógica de negócio.
Uma configuração inicial comum é:
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);O NestJS documenta whitelist para remover propriedades que não possuem decorators de validação e forbidNonWhitelisted para rejeitar requisições contendo propriedades não permitidas. transform permite converter os valores recebidos para os tipos definidos no DTO.
Checklist:
-
ValidationPipeglobal. - DTOs específicos para entrada.
- Campos obrigatórios explicitamente validados.
- Enumerações validadas.
- Tamanhos máximos definidos.
- Strings com regras apropriadas.
- IDs validados.
- Paginação limitada.
- Propriedades inesperadas rejeitadas ou removidas.
5. Nunca confie no TypeScript como mecanismo de segurança
Isto:
createUser(dto: CreateUserDto)não impede que uma requisição HTTP envie qualquer JSON.
TypeScript fornece segurança durante o desenvolvimento, mas a entrada da aplicação vem da rede e precisa ser validada em runtime.
Em outras palavras:
TypeScript ≠ validação de entradaA validação precisa acontecer na fronteira entre a aplicação e o mundo externo.
6. Configure CORS explicitamente
CORS não deve ser tratado como:
app.enableCors();sem avaliar o cenário da aplicação.
Defina explicitamente quais origens podem consumir sua API.
Por exemplo:
app.enableCors({
origin: [
'https://app.exemplo.com',
],
credentials: true,
});O NestJS permite configurar CORS diretamente na aplicação e utiliza as opções oferecidas pelo adaptador HTTP escolhido.
Evite liberar origens indiscriminadamente em ambientes que trabalham com autenticação por cookies.
Também é importante lembrar:
CORS não substitui autenticação ou autorização.
Ele controla quais navegadores podem realizar determinadas requisições cross-origin; não impede que outro cliente HTTP envie requisições diretamente à API.
7. Proteja aplicações que utilizam cookies contra CSRF
Se sua autenticação utiliza cookies enviados automaticamente pelo navegador, avalie a necessidade de proteção contra Cross-Site Request Forgery (CSRF).
O NestJS documenta o uso de mecanismos específicos de proteção contra CSRF, incluindo o pacote csrf-csrf para aplicações Express.
Além disso, cookies de autenticação devem ser avaliados quanto a atributos como:
HttpOnly
Secure
SameSiteA estratégia precisa considerar como frontend, backend e domínio de autenticação estão estruturados.
Uma API que utiliza exclusivamente:
Authorization: Bearer <token>possui um modelo diferente de uma aplicação que depende de sessão autenticada por cookie.
8. Limite tentativas de login e operações sensíveis
Endpoints como:
POST /auth/login
POST /auth/forgot-password
POST /auth/reset-password
POST /auth/verify-code
POST /auth/send-codenão devem aceitar tentativas ilimitadas.
O NestJS disponibiliza o @nestjs/throttler para implementar rate limiting e proteção contra ataques como brute force.
Exemplo:
ThrottlerModule.forRoot({
throttlers: [
{
ttl: 60_000,
limit: 10,
},
],
});Mas não use necessariamente a mesma política para toda a aplicação.
Uma requisição de:
GET /productspode ter uma política completamente diferente de:
POST /auth/loginTambém considere que, em ambientes com múltiplas instâncias, a estratégia de armazenamento do rate limiter precisa ser compatível com a arquitetura distribuída.
9. Não armazene senhas em texto puro
Senhas não devem ser armazenadas como:
senha123nem criptografadas de maneira reversível.
Elas devem ser armazenadas utilizando um algoritmo apropriado de password hashing.
A própria documentação do NestJS recomenda bibliotecas como bcrypt ou argon2 para hashing de senhas.
Exemplo:
const hash = await bcrypt.hash(password, 12);E para verificar:
const valid = await bcrypt.compare(password, hash);Nunca crie seu próprio algoritmo de hashing.
10. Secrets não devem estar no Git
Procure pelo repositório:
JWT_SECRET=
DATABASE_PASSWORD=
AWS_SECRET_ACCESS_KEY=
API_KEY=
PRIVATE_KEY=Secrets não devem ser commitados no código.
O OWASP recomenda uma abordagem de gerenciamento de secrets que considere armazenamento, provisionamento, auditoria, controle de acesso e rotação.
Use mecanismos apropriados para cada ambiente:
Development → .env local
Staging → secret manager / environment
Production → secret manager / environmentE não esqueça de revisar:
.gitignore
Docker images
CI/CD logs
build artifacts
backups
logsRemover um secret do arquivo atual não resolve necessariamente um vazamento que já entrou no histórico do Git.
11. Valide também as variáveis de ambiente
Um erro comum é iniciar a aplicação com uma configuração incompleta:
DATABASE_URL=
JWT_SECRET=
REDIS_HOST=e descobrir o problema apenas depois que determinadas rotas forem utilizadas.
O NestJS suporta validação de configuração durante o bootstrap da aplicação. A documentação atual também apresenta opções baseadas em schemas como Zod e outras implementações compatíveis.
A aplicação deveria falhar rapidamente quando uma variável obrigatória está ausente ou inválida.
Isso é muito melhor do que iniciar parcialmente configurada.
12. Use HTTPS
Nunca trate HTTPS como responsabilidade exclusiva do frontend.
Toda comunicação envolvendo:
- credenciais;
- tokens;
- dados pessoais;
- informações financeiras;
- informações administrativas;
deve utilizar transporte protegido.
Em produção, verifique também:
HTTP → HTTPS
HSTS
TLS configuration
Secure cookies
Proxy configurationSe houver um reverse proxy, confirme que a aplicação conhece corretamente o esquema e o IP original quando isso impactar autenticação, logs ou rate limiting.
13. Configure headers de segurança
Aplicações HTTP podem utilizar headers para ativar mecanismos de proteção no navegador.
O NestJS atualmente possui app.useSecurityHeaders() para definir headers de segurança com os defaults da implementação baseada no Helmet 8. Também é possível utilizar Helmet diretamente.
Exemplo:
const app = await NestFactory.create(AppModule);
app.useSecurityHeaders();Para aplicações compatíveis com versões anteriores do NestJS, Helmet continua sendo uma alternativa documentada:
import helmet from 'helmet';
app.use(helmet());A configuração precisa ser testada com recursos como Swagger, GraphQL IDEs e outros componentes que possam ser afetados por CSP.
14. Não exponha informações sensíveis nas mensagens de erro
Evite respostas como:
{
"error": "SQLSTATE[HY000]: Access denied for user..."
}ou:
{
"error": "/var/www/app/src/modules/users/users.service.ts:42"
}Em produção, mensagens de erro precisam ser úteis para o cliente sem revelar:
- stack trace;
- caminhos internos;
- credenciais;
- queries;
- nomes internos de serviços;
- detalhes da infraestrutura.
O detalhe completo deve estar disponível para observabilidade interna, e não necessariamente para o usuário.
15. Não registre secrets nos logs
Tenha atenção especial aos logs de:
Authorization
Cookie
password
refreshToken
accessToken
apiKey
clientSecretNão faça:
logger.debug(request.body);
logger.debug(request.headers);sem entender o conteúdo desses objetos.
Logs são extremamente úteis para investigação de incidentes, mas precisam ser tratados como dados potencialmente sensíveis. O OWASP recomenda que eventos de segurança sejam registrados de forma consistente e utilizável para investigação e correlação.
16. Não confie apenas na validação do frontend
Este código:
if (password.length < 8) {
// ...
}no React, Vue ou Angular não protege a API.
Um atacante pode ignorar completamente a interface e executar:
curlou criar seu próprio cliente HTTP.
Toda regra de segurança relevante precisa ser validada no backend.
17. Cuidado com SQL e NoSQL Injection
Nunca construa queries concatenando diretamente dados recebidos do usuário.
Evite:
const query = `
SELECT *
FROM users
WHERE email = '${email}'
`;Prefira mecanismos parametrizados fornecidos pelo ORM ou pelo driver.
A mesma preocupação vale para:
- SQL;
- MongoDB;
- Redis;
- mecanismos de busca;
- filtros dinâmicos;
- comandos externos.
O uso de um ORM reduz alguns riscos, mas não transforma automaticamente todo código em seguro.
18. Limite paginação e quantidade de resultados
Uma rota como:
GET /usersnão deveria permitir:
GET /users?limit=999999999Defina limites:
page >= 1
limit >= 1
limit <= 100Isso ajuda a reduzir:
- consumo excessivo de memória;
- consultas pesadas;
- respostas gigantes;
- abuso automatizado.
Esse cuidado também está relacionado ao conceito de Unrestricted Resource Consumption, listado pelo OWASP como API4.
19. Cuidado com uploads de arquivos
Upload é uma superfície de ataque por si só.
Não confie apenas na extensão:
arquivo.jpgVerifique pelo menos:
- tamanho máximo;
- MIME type;
- extensão permitida;
- conteúdo real quando necessário;
- quantidade de arquivos;
- nome do arquivo;
- local de armazenamento;
- necessidade de antivírus ou sandbox;
- possibilidade de execução do arquivo.
O NestJS disponibiliza mecanismos para upload de arquivos, mas esses recursos precisam ser configurados de acordo com os requisitos da aplicação.
Nunca salve uploads diretamente em um diretório onde o servidor possa executá-los.
20. Proteja endpoints de download
Não basta esconder o link de um arquivo.
Evite:
GET /files/123retornar o arquivo simplesmente porque o ID existe.
Verifique:
usuário autenticado
recurso pertence ao usuário
usuário possui permissão
arquivo ainda está disponívelUm endpoint de download precisa aplicar autorização exatamente como qualquer outro recurso da API.
21. Proteja integrações externas contra SSRF
Cuidado com endpoints como:
POST /fetch-urlrecebendo:
{
"url": "https://exemplo.com"
}Se o backend realiza requisições arbitrárias para URLs fornecidas pelo usuário, pode surgir uma vulnerabilidade de Server-Side Request Forgery (SSRF).
O OWASP inclui SSRF como API7 no API Security Top 10.
Quando possível:
- utilize allowlists de hosts;
- bloqueie redes internas;
- bloqueie localhost;
- valide redirects;
- limite tempo de conexão;
- limite tamanho da resposta;
- evite permitir protocolos desnecessários.
22. Valide webhooks recebidos
Integrações como:
Stripe
GitHub
Mercado Pago
PagSeguro
sistemas internos
provedores de autenticaçãopodem enviar webhooks.
Não confie apenas no IP de origem.
Sempre que o provedor disponibilizar esse mecanismo, valide:
assinatura
timestamp
payload
idempotênciaTambém armazene identificadores de eventos processados para evitar que o mesmo evento seja executado várias vezes.
23. Implemente idempotência onde necessário
Operações como:
criar pagamento
emitir documento
criar pedido
enviar cobrança
processar webhookpodem receber a mesma requisição mais de uma vez.
Uma aplicação segura não deve transformar um retry em múltiplas operações financeiras ou administrativas.
Quando apropriado, utilize uma chave de idempotência:
Idempotency-Key: 9c3d...e garanta que a operação seja processada uma única vez.
24. Controle acesso a funções administrativas
Rotas como:
POST /admin/users
DELETE /admin/users/:id
GET /admin/audit
POST /admin/settingsmerecem uma camada adicional de autorização.
Não dependa somente de:
if (user.role === 'admin')espalhado pela aplicação.
Centralize as regras utilizando Guards, policies ou outro mecanismo consistente.
O NestJS oferece exemplos de RBAC e também suporta outras estratégias de autorização.
25. Não exponha endpoints internos desnecessariamente
Revise a API em busca de rotas como:
/debug
/test
/internal
/admin
/metrics
/swagger
/api-jsonNem todo endpoint existente durante o desenvolvimento precisa estar publicamente acessível.
A documentação Swagger também merece atenção. O NestJS expõe tanto a interface quanto o documento OpenAPI configurado pela aplicação.
Em produção, avalie:
Swagger protegido por autenticação
Swagger somente em rede interna
Swagger desabilitadoO importante é tomar essa decisão conscientemente.
26. Faça inventário dos endpoints
Uma API grande pode possuir:
/users
/users/:id
/orders
/orders/:id
/admin
/internal
/webhooks
/debugsem que todos tenham a mesma política de segurança.
Faça uma revisão periódica da superfície exposta.
Para cada endpoint, documente:
Método
URL
Autenticação
Autorização
Dados recebidos
Dados retornados
Rate limit
SensibilidadeIsso ajuda a encontrar endpoints esquecidos ou inconsistentes.
O OWASP API Security Top 10 também destaca Improper Inventory Management como API9.
27. Retorne somente os campos necessários
Imagine:
return user;e a entidade contém:
id
name
email
passwordHash
refreshToken
resetToken
internalNotesMesmo que o framework serialize automaticamente o objeto, isso pode gerar vazamento de informações.
Prefira DTOs de resposta:
export class UserResponseDto {
id: string;
name: string;
email: string;
}A resposta da API deve ser uma decisão explícita.
28. Atualize dependências e faça auditoria
Uma aplicação NestJS não é composta apenas pelo código que você escreveu.
Ela depende de:
NestJS
Express/Fastify
ORM
JWT
bcrypt/argon2
Swagger
Redis
RabbitMQ
bibliotecas auxiliaresInclua verificações no CI/CD:
npm audite mantenha as dependências atualizadas de maneira controlada.
Também monitore vulnerabilidades relevantes em dependências transitivas.
29. Faça testes de segurança automatizados
Antes do deploy, teste pelo menos:
401 → endpoint sem autenticação
403 → usuário sem permissão
404 → recurso inexistente
400 → payload inválido
429 → excesso de requisições
413 → payload grande demaisTeste também cenários como:
usuário A acessando recurso de B
usuário comum acessando endpoint administrativo
token expirado
token inválido
refresh token reutilizado
ID manipulado
campo extra no payload
upload inválido
URL externa maliciosaO objetivo não é apenas testar se o “caminho feliz” funciona.
O objetivo é provar que os caminhos proibidos realmente estão bloqueados.
30. Revise a infraestrutura junto com o código
Uma API segura pode continuar vulnerável por causa da infraestrutura.
Antes de colocar NestJS em produção, revise:
HTTPS
Firewall
Reverse proxy
Banco de dados
Redis
Filas
Docker
Volumes
Secrets
Backups
SSH
Logs
Monitoring
AlertasNunca exponha diretamente na internet serviços como:
PostgreSQL
MySQL
Redis
RabbitMQ
MongoDBsem necessidade.
A superfície pública idealmente deve ser pequena:
Internet
↓
Reverse Proxy / Load Balancer
↓
NestJS
↓
Serviços internosUm main.ts como ponto de partida
Uma configuração inicial pode concentrar várias dessas proteções:
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api');
app.enableCors({
origin: ['https://app.example.com'],
credentials: true,
});
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
// NestJS atual:
app.useSecurityHeaders();
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();A configuração exata depende do adaptador HTTP, versão do NestJS, estratégia de autenticação e arquitetura da aplicação. Para versões que não possuem useSecurityHeaders(), Helmet continua sendo uma alternativa documentada.
Checklist rápido antes do deploy
Use esta lista como revisão final:
[ ] HTTPS obrigatório
[ ] Authentication implementada
[ ] Authorization implementada
[ ] Guards protegendo endpoints privados
[ ] DTOs definidos
[ ] ValidationPipe global
[ ] whitelist habilitado
[ ] Mass assignment revisado
[ ] CORS configurado explicitamente
[ ] CSRF avaliado
[ ] Rate limiting configurado
[ ] Brute force protegido
[ ] Senhas com bcrypt/Argon2
[ ] JWT com expiração adequada
[ ] Secrets fora do Git
[ ] Variáveis de ambiente validadas
[ ] Erros sem informações sensíveis
[ ] Logs sem tokens ou passwords
[ ] SQL/NoSQL injection revisado
[ ] Paginação com limite
[ ] Uploads restritos
[ ] Downloads autorizados
[ ] SSRF revisado
[ ] Webhooks com assinatura validada
[ ] Operações críticas idempotentes
[ ] Endpoints administrativos protegidos
[ ] Swagger/API docs protegidos
[ ] Endpoints antigos/internos removidos
[ ] Dependências auditadas
[ ] Testes de segurança automatizados
[ ] Infraestrutura revisadaSegurança não é um middleware
Uma das maiores armadilhas ao trabalhar com NestJS é acreditar que instalar Helmet, ativar CORS e configurar JWT significa que a aplicação está segura.
Essas ferramentas são importantes, mas representam apenas uma parte do problema.
A segurança de uma API acontece em várias camadas:
Internet
│
▼
HTTPS / Proxy
│
▼
Rate Limiting
│
▼
Authentication
│
▼
Authorization
│
▼
Validation
│
▼
Business Rules
│
▼
DatabaseE cada camada precisa assumir que a anterior pode ser insuficiente.
Uma requisição autenticada ainda pode não ser autorizada.
Uma requisição autorizada ainda pode conter dados inválidos.
Um dado válido ainda pode abusar de um recurso.
E uma aplicação corretamente protegida ainda pode expor secrets através de logs ou da infraestrutura.
Por isso, o melhor momento para aplicar esse checklist não é depois de um incidente.
É antes do primeiro deploy.
Referências
- NestJS — Authentication
- NestJS — Authorization
- NestJS — Validation
- NestJS — Rate Limiting
- NestJS — Security Headers / Helmet
- NestJS — CORS
- NestJS — CSRF Protection
- NestJS — Encryption and Hashing
- NestJS — File Upload
- OWASP API Security Top 10
- OWASP Secrets Management Cheat Sheet
- OWASP Logging Cheat Sheet