Como funciona esta verificação
O Scanaris pede uma lista de caminhos onde costumam ficar ficheiros que nunca deviam estar num servidor público: .env, .env.local, .env.production, .git/config, .git/HEAD, wp-config.php, config.json, docker-compose.yml, backup.sql, phpinfo.php, .npmrc, Dockerfile, .gitlab-ci.yml, .aws/credentials, .ssh/id_rsa, web.config, adminer.php e .DS_Store. Um 200 não basta para marcar nada: muitas aplicações de página única respondem 200 com o seu HTML a qualquer caminho. Por isso o scanner confirma que o conteúdo parece real, por exemplo que um .env tem linhas CHAVE=valor e não é HTML, ou que .git/HEAD começa por ref:. A severidade depende do ficheiro: crítica para .env, cópias da base de dados e chaves privadas; alta para .git e configurações de servidor; baixa para .DS_Store ou um Dockerfile.
O que um atacante faz com isto
O mesmo que o scanner, mas contra todos os domínios que existem. Um .env acessível entrega as credenciais da base de dados, as chaves de pagamento e os tokens de email de uma vez. Um diretório .git exposto permite descarregar o repositório completo com uma ferramenta de linha de comandos, com todo o histórico, incluindo as chaves apagadas num commit posterior. Um backup.sql é a tua base de dados inteira, com utilizadores e palavras-passe cifradas. É uma das falhas mais simples de explorar e mais graves.
Porque acontece
Duas causas. A primeira é fazer deploy da pasta do projeto inteira em vez da pasta de saída do build: tudo o que está no repositório passa a poder ser servido. A segunda é um servidor web (nginx, Apache, IIS) a servir uma pasta onde também se desenvolve ou se fazem cópias de segurança. Plataformas como a Vercel ou a Netlify só publicam a pasta de saída, por isso aí esta falha costuma reduzir-se a ficheiros copiados por engano para public/.
Como corrigir
- Tira o ficheiro e roda tudo o que ele continha. Se um
.envesteve acessível, cada chave lá dentro está comprometida mesmo que ninguém te tenha avisado. - Faz deploy só da saída do build (
dist/,.output/,.next/), nunca da raiz do projeto. Em Express, oexpress.staticdeve apontar para essa pasta. - Bloqueia os caminhos no servidor como segunda barreira. Em nginx:
location ~ /\.(?!well-known) { deny all; }bloqueia tudo o que começa por ponto exceto.well-known; acrescenta regras para*.sql,*.ymle*.log. Em Apache, o equivalente comFilesMatcheRequire all denied. - Revê a pasta public/ do teu projeto: aí não deve haver nada que não seja uma imagem, uma fonte ou um ficheiro pensado para ser descarregado.
- Vê os registos de acesso à procura de pedidos a
/.envou/.gitcom resposta 200 para saberes se alguém chegou antes de ti.
Confirma que está corrigido
for p in .env .env.local .git/config .git/HEAD config.json backup.sql docker-compose.yml .npmrc; do
printf "%-20s " "$p"; curl -s -o /dev/null -w "%{http_code}\n" "https://oteudominio.com/$p"
done
O esperado é 404 ou 403 em todos. Um 200 numa SPA pode ser o HTML de sempre: abre-o e confirma que não é o ficheiro real.
Perguntas frequentes
O meu site devolve 200 em todos os caminhos. Vai marcar falsos positivos?
Não. O scanner valida o conteúdo antes de abrir um achado; um HTML genérico não conta como .env.
Porque é que o .DS_Store é um achado se não contém segredos?
Porque lista os nomes dos ficheiros da pasta, incluindo os que não ligas a partir de nenhuma página. É um mapa gratuito para quem procura cópias de segurança ou ficheiros esquecidos. Severidade baixa, mas convém tirá-lo.
E os caminhos .well-known?
Esses devem ser acessíveis: aí vivem o security.txt, as verificações de domínio e os certificados. A regra de nginx do exemplo exclui-os do bloqueio.