Voltar ao blog
27 de outubro de 2025Sergei Solod5 min de leitura

Meu site Next.js estático recebe milhares de scans de vulnerabilidade por dia. O Nginx quase não percebe

Meus logs estão cheios de probes procurando WordPress, backdoors PHP, .env e .git/config. No meu setup estático com Next.js + Nginx, a maioria termina em misses baratos e 404, enquanto a carga da CPU permaneceu estável. Eis o que essa experiência realmente diz sobre segurança de sites estáticos — e o que ela não prova.

SegurançaNext.jsNginxDevOpsHospedagem estáticaSuperfície de ataque

Todos os dias, os logs do meu servidor registram milhares de scans automatizados de vulnerabilidade. As requisições parecem bem ameaçadoras:

  • /wp-admin/wp.php
  • /111.php
  • /code.php
  • /.git/config
  • /i.php
  • /admin
  • /api/.env
  • /kal.php

O que me surpreendeu não foi a quantidade, mas o pouco que o servidor parecia sentir. Enquanto eu observava esse tráfego, a carga da CPU não apresentou mudança visível.

A observação é real, mas minha explicação original era absoluta demais. Entrega estática não é um escudo mágico e um 404 não é de graça. A vantagem concreta da minha arquitetura é mais específica: muitas probes oportunistas têm custo baixo porque quase não existe lógica de aplicação server-side no caminho público para elas alcançarem.

São probes, não prova de comprometimento

Ao ver /wp-admin/wp.php ou /111.php, é tentador chamar toda requisição de “exploit”. Tecnicamente isso é impreciso. O que vejo principalmente é probing automatizado: bots testam nomes de arquivos e endpoints comuns e observam o que responde.

Alguns caminhos miram claramente WordPress ou PHP. Outros, como /.git/config e /api/.env, procuram configurações ou secrets publicados por engano. /admin é ainda mais genérico e pode ser uma rota legítima. Uma requisição suspeita me mostra o que o scanner procura, não que a vulnerabilidade exista.

No meu caso, o ponto decisivo é a arquitetura: o site público é HTML estático pré-renderizado pelo Next.js e servido diretamente pelo Nginx.

Por que esse tráfego é barato no meu stack

Nas páginas de que estou falando, não há um runtime PHP nem um banco de dados atrás de cada request. O Nginx serve arquivos que já existem. Se um scanner pede /111.php e o arquivo não existe, nenhuma aplicação PHP é iniciada, nenhum código WordPress é executado e nenhuma query de banco acontece. A requisição simplesmente dá miss e termina em 404.

Isso muda o modelo de custo. Em uma aplicação dinâmica, uma request pode passar por routing, framework, autenticação, rendering, banco de dados ou outros serviços. Meu caminho estático tem muito menos peças móveis. O Nginx ainda precisa aceitar a conexão, processar HTTP, procurar o recurso, escrever logs e enviar a resposta, mas o trabalho da aplicação é pequeno.

Também uso caching agressivo no site, o que ajuda na entrega normal de conteúdo estático. Mesmo assim, eu não daria ao cache o crédito por toda 404 aleatória. Uma URI nova e inexistente ainda pode passar pelo processamento normal do Nginx e por um filesystem lookup antes de receber 404.

A correção importante: estático não significa “seguro por definição”

Esta é a parte que eu escreveria com mais cuidado hoje. Uma arquitetura estática remove muitos componentes server-side do caminho público, mas não elimina o trabalho de segurança.

  • Um arquivo exposto continua exposto. Se .git, um .env, um backup ou um secret parar no diretório público, o Nginx pode servi-lo tão eficientemente quanto HTML se a configuração não bloquear.
  • Nginx, TLS, sistema operacional e rede continuam na attack surface. Eles ainda precisam de patches e configuração adequada.
  • Código client-side ainda pode ter vulnerabilidades. HTML estático não torna automaticamente seguros JavaScript, lógica de autenticação no navegador ou third-party scripts.
  • Resource exhaustion continua possível. Conexões, banda, TLS handshakes, workers, log I/O e espaço em disco são finitos. Tráfego suficiente pode afetar até um site estático.

Então a conclusão correta não é “essas requests não importam”, mas: muitas probes específicas de aplicações não encontram nada para executar nessa arquitetura.

“Milhares de scans por dia” pode soar pior do que a carga real

Os logs tornam o background noise da Internet muito visível porque cada probe falha aparece como uma linha. Mas o total diário, sozinho, não mede impacto operacional. Alguns milhares de requests distribuídos por 24 horas são muito diferentes do mesmo volume chegando em um burst curto.

CPU também é apenas um sinal. No meu caso ela permaneceu estável, o que é uma evidência útil de que esse tráfego não estava criando pressão de compute perceptível naquele momento. Isso não prova custo zero em outros recursos. Para avaliar direito eu também olharia request rate, bandwidth, conexões ativas, uso dos workers do Nginx, response latency, volume de logs e uso de disco.

O que aprendi observando esse ruído

A principal lição para mim é que a arquitetura pode tornar categorias inteiras de ataques automatizados pouco relevantes sem exigir uma regra para cada scanner signature. Um bot pode procurar backdoors WordPress e PHP o dia inteiro; se o caminho público não tem WordPress nem PHP, essas probes têm muito pouco para explorar.

Mas eu não confundo mais “irrelevante para meu stack” com “tráfego inofensivo”. Minha checklist atual é simples:

  • Saber quais runtimes e serviços são realmente alcançáveis pelo caminho público.
  • Manter secrets, repository metadata, backups e build artifacts fora do web root ou bloqueá-los explicitamente.
  • Tratar probes repetitivas que viram 404 como background noise normal da Internet enquanto não houver outras evidências de targeting ou impacto.
  • Não concluir que abusive traffic é gratuito olhando só para CPU.
  • Manter Nginx, OS, bibliotecas TLS e dependencies atualizados mesmo quando a aplicação é estática.

O que esta experiência não prova

Eu não rodei um benchmark controlado e não simulei DDoS. Apenas observei production logs e a carga do servidor enquanto milhares de scanner requests chegavam todos os dias. Isso basta para uma conclusão prática sobre meu setup, não para uma regra universal de que “estático sempre vence”.

O que posso confirmar com precisão é mais limitado: no meu Next.js static export servido pelo Nginx, a maior parte do scanner traffic observado terminou em file misses baratos e 404, em vez de alcançar um runtime PHP ou uma aplicação com banco de dados. A carga da CPU permaneceu igual durante a observação.

É essa vantagem de resilience que me interessa. Menos peças móveis não tornam um sistema invulnerável. Elas apenas dão ao ruído aleatório da Internet menos lugares onde virar trabalho real de aplicação.