Guias de Segurança

Você deixou um arquivo de segredo em um diretório público? Audite seu webroot

Um token, .env ou backup no webroot pode ser baixado por qualquer um pela URL. Como templates espalham o mesmo arquivo e como auditar seus servidores.

Publicado 2026-06-11 Atualizado 2026-10-06 16 min de leitura
Nesta página

Para: qualquer pessoa que rode vários sites em hospedagem compartilhada/alugada ou em um VPS, fazendo deploy em diretórios públicos (public/, public_html/, htdocs/ etc.). Nenhum passo de ataque — só auditar o seu próprio servidor e fechar os buracos. Para proteger o próprio .env, veja protegendo o .env em hospedagem compartilhada.

A visão deste site: onde você coloca É o controle de acesso

Segredos vazam mais por acidentes de posicionamento do que por ataques engenhosos. O webroot é "um lugar de onde qualquer um pode vir baixar pela URL." Coloque um segredo ali e até a senha de servidor mais forte fica sem sentido. A regra básica deste site é manter segredos fora tanto do webroot quanto do git (→ guardando segredos com segurança). A ideia é simples: coloque no diretório público só coisas que você não se importa que qualquer um veja.

public/ = baixável por qualquer um via URL

OK colocar

imagens, CSS, JS — assets públicos

Nunca colocar

.env, token.json, .sql, .git, .bak

Acima da raiz do app = não servido

Coloque aqui

segredos, tokens, credenciais, backups. Permissão 600 (leitura só do dono). Inalcançável por URL.

Arquivos no diretório público podem ser baixados por qualquer um via URL. Mantenha segredos fora dele (não servidos, permissão 600).

Por que "resquícios no diretório público" acontecem

O padrão comum é um arquivo colocado por conveniência, ou um que veio dentro de um boilerplate, ficando silenciosamente público.

uma URL
um arquivo no webroot é baixável por qualquer um
anos
ele fica despercebido
todo site
resquícios de template se espalham para todos os sites
revogue já
presuma que vazou e rotacione

Por exemplo, um JSON guardando um token de acesso para uma integração de terceiros fica sob public/ por muito tempo — e se for de um template compartilhado, o mesmo arquivo é copiado para o mesmo ponto em muitos sites, então todos compartilham o mesmo problema. Corrigir um site não adianta nada se os outros ainda têm o arquivo. Igualmente perigosos: .env esquecidos, backups de banco de dados (.sql), um diretório .git, backups de editor (*.bak) e atalhos (relacionado: path traversal · um .env inteiro exposto).

Arquivos que ficam para trás, e por que cada um é perigoso

"Arquivo de segredo" costuma lembrar o .env, mas o que de fato fica para trás é bem mais amplo. O guia de testes da OWASP (uma organização sem fins lucrativos focada em segurança web) também lista versões antigas de arquivos, backups e arquivos sem nenhum link apontando para eles como itens a verificar.

TipoNomes típicosO que está em riscoOnde deveria ficar
Arquivos de configuração.env, config.php.bak, settings.jsonSenhas de banco de dados e chaves de API escritas em texto puroAcima da raiz do app (não servido)
Tokens e credenciaistoken.json, credentials.json, *.pem, *.keyLogin direto num serviço externo ou em outro servidorFora do webroot, permissão 600
Backups manuais ou do editorlogin.php.old, index.php~, .index.php.swp, *.origCom a extensão trocada, o arquivo pode não ser executado como código, então o código-fonte aparece como texto puroNão os crie em produção; edite localmente
Dumps de banco de dadosbackup.sql, dump.sql.gzDados pessoais dos usuários e hashes de senha, tudo num arquivo sóUm local dedicado a backups, de preferência fora do servidor
Arquivos compactados do sitesite.zip, www.tar.gzContêm o .env e o código-fonte completoApague logo depois de extrair
Dados de controle de versão.git/Segredos de commits antigos podem ser recuperáveisFora do diretório público
Valores embutidos no builddentro de assets/index-xxxx.jsVariáveis que começam com VITE_ ou NEXT_PUBLIC_ acabam no JavaScript do navegadorMantenha segredos só em variáveis do lado do servidor

A última linha é fácil de deixar passar. Mesmo que você nunca tenha colocado um arquivo ali, um build pode empurrar um segredo para o diretório público. A documentação oficial do Vite diz claramente que variáveis VITE_ não devem conter informações sensíveis, como chaves de API.

Audite o seu próprio servidor

Primeiro, revele mecanicamente "quaisquer arquivos com cara de segredo no meu próprio diretório público." Isto é inspecionar os seus próprios ativos, não espiar o site de outra pessoa.

1

Procure sob os diretórios públicos por arquivos com cara de segredo

Em toda a sua home, revele candidatos a segredo que escorregaram para public/ (JSON de token/credenciais, .env, chaves, atalhos).
2

Presuma que o mesmo arquivo existe em outros lugares — verifique todo host e site

Sites construídos do mesmo boilerplate têm a mesma coisa no mesmo lugar; rode a mesma verificação em todos os hosts e sites. Uma ocorrência normalmente significa que há mais.
3

Decida por arquivo se ele realmente precisa ser público

Classifique cada resultado em "seguro publicar" vs. "segredo". Os segredos passam pelos passos de remover/revogar/mover abaixo.
# audit under your own public directories (inspecting your own assets)
find ~ -path '*/public/*' \( -iname '*token*.json' -o -iname '*credential*.json' \
      -o -iname '*.bak' -o -iname '*.sql' -o -iname '.env*' \) 2>/dev/null
# an exposed .git directory is dangerous too
find ~ -path '*/public/*/.git' -maxdepth 8 2>/dev/null

Como verificar o seu próprio ambiente

O find acima é um ponto de partida. Percorrer as cinco verificações abaixo pega resquícios que uma busca só por nome de arquivo deixa passar. Rode-as apenas no seu próprio servidor e no seu próprio domínio. As verificações específicas do .env (olhar os primeiros bytes da resposta, confirmar que o .htaccess funciona de fato) estão em protegendo o .env em hospedagem compartilhada.

1

Procure também backups e arquivos compactados

O nome do diretório público varia conforme a hospedagem, então inclua public_html, htdocs e www. Por exemplo, rode find ~/public_html \( -name '*~' -o -name '*.swp' -o -name '*.old' -o -name '*.orig' -o -name '*.zip' -o -name '*.tar.gz' -o -name '*.pem' -o -name '*.key' \) 2>/dev/null e confirme, arquivo por arquivo, que cada resultado deve mesmo ser público.

2

Confirme que a listagem de diretórios está desativada

Abra no navegador um diretório que não tem index.html (por exemplo /uploads/). Se você vir uma lista de nomes de arquivos, o recurso de listagem de diretórios do servidor web está ativado. Uma listagem permite que as pessoas encontrem resquícios sem saber os nomes. Um 403 ou 404 é o que você quer.

3

Procure segredos no JavaScript gerado pelo build

Se você faz build de um frontend, pesquise a pasta de saída que vai para o deploy (dist/, .next/static/ e similares). Use algo como grep -rlE 'BEGIN [A-Z ]*PRIVATE KEY|secret|password' dist/, mais o prefixo que o seu serviço usa nas chaves. Se encontrar algo, verifique se a variável tem um nome voltado ao navegador (VITE_, NEXT_PUBLIC_).

4

Confira se os segredos fora do webroot não são legíveis por outros usuários

Tirar um segredo do webroot não adianta se permissões frouxas deixam outra conta do mesmo servidor lê-lo. find ~ -maxdepth 3 \( -name '.env*' -o -name '*.pem' -o -name '*token*.json' \) -perm /o+r 2>/dev/null lista segredos legíveis por qualquer um além do dono; corrija com chmod 600. Sem saída significa que está tudo certo.

5

Verifique se os buscadores indexaram algo

Pesquise no Google site:seudominio e procure arquivos que você não reconhece (.sql, .zip, .txt e outros). Se você usa o Search Console, o relatório Páginas lista as URLs indexadas. O que fazer se algo ainda está nos resultados de busca está em erros comuns, abaixo.

O que fazer quando você acha um

Faça três coisas como um conjunto — remover, revogar, mover. Pule qualquer uma e a correção fica incompleta.

1

Remova do webroot para que a URL não consiga baixá-lo

Mova o arquivo para fora do diretório público ou apague-o, e confirme que a URL agora retorna 404.
2

Revogue/reemita qualquer chave ou token que possa ter vazado

Não deixe em "provavelmente está tudo bem." Como ficou exposto, presuma que vazou e renove ou revogue aquele token/chave.
3

Mantenha segredos fora do webroot com permissão 600

De agora em diante, coloque segredos fora do diretório público (ex.: acima da raiz do app) com permissão 600 (leitura só do dono). Se sua configuração puder negar o serviço de extensões sensíveis, adicione isso também.

Por servidor: configurações que se recusam a servir esses arquivos (como reforço)

A correção real é não colocar os arquivos ali. Além disso, acrescente uma regra de bloqueio no servidor web para que algo colocado por engano ainda assim não seja servido. O que dá para usar depende da sua configuração.

ConfiguraçãoComo bloquearListagem de diretóriosAtenção
Apache (VPS)<FilesMatch> + Require all denied num bloco <Directory> ou no .htaccessDesative com Options -IndexesNo Apache 2.4 o AllowOverride tem padrão None, então o .htaccess é ignorado a menos que você o permita
Nginx (VPS)deny all; dentro de um locationautoindex é off por padrãoNão lê .htaccess. Blocos location com regex são verificados na ordem em que foram escritos, e o primeiro que casar vence
Hospedagem compartilhadaNormalmente .htaccess (compatível com Apache)Pelo painel de controle ou pelo .htaccessConfirme que funciona com um arquivo de teste que não contenha segredos
Hospedagem estática / CDNO que estiver na pasta de saída é publicado como estáDepende do serviçoConte com manter segredos fora da pasta de saída, não com regras de bloqueio

Exemplo para Apache (onde o .htaccess está habilitado):

Options -Indexes
<FilesMatch "(^\.|~$|\.(bak|old|orig|swp|sql|zip|tar|gz|pem|key)$)">
    Require all denied
</FilesMatch>

Exemplo para Nginx (dentro de um bloco server):

# Allow the path used for automatic certificate renewal (Let's Encrypt) first
location ^~ /.well-known/acme-challenge/ { }
 
# Deny files and directories starting with a dot (.env, .git, ...)
location ~ /\. { deny all; }
 
# Deny backups and archives
location ~* (~|\.(bak|old|orig|swp|sql|zip|tar|gz|pem|key))$ { deny all; }

No Nginx, quando uma requisição casa com um location marcado com ^~, os locations com regex não são verificados. Assim, /.well-known/acme-challenge/, usado na renovação de certificados, continua sendo servido apesar da regra que bloqueia caminhos iniciados por ponto. Depois de mudar a configuração, confira a sintaxe com nginx -t, recarregue e confirme que um arquivo de teste retorna 403. Se o seu site oferece arquivos ZIP ou similares para download, tire essa extensão da lista de bloqueio.

O posicionamento em que as pessoas caem (perigoso)

  • um token JSON para uma integração fica em public/
  • um arquivo de segredo que veio no boilerplate permanece público
  • backups (.sql/.bak) ou .git deixados sob o diretório público
  • corrigir um site e considerar "resolvido"

O posicionamento correto

  • o diretório público contém só coisas que podem ser públicas
  • segredos ficam fora do webroot com permissão 600
  • extensões sensíveis têm o serviço negado
  • ache um e audite todo host e site

Faça de 'só coisas seguras para o público' uma regra permanente

Regras vencem correções pontuais. Decida que o diretório público contém só arquivos seguros para o público e, por regra, nunca coloque ali segredos, backups, dados de controle de versão (.git) ou arquivos de configuração. Ao atualizar um boilerplate, retire o segredo do próprio template — senão todo site que você produzir em massa a seguir continua copiando o mesmo arquivo de segredo.

Erros comuns e como corrigi-los

  • Confiar numa regra de bloqueio e deixar o arquivo no lugar: uma mudança de servidor ou uma reescrita da configuração pode derrubar a regra, e o arquivo fica público a partir desse dia. O Nginx nem lê o .htaccess. Trate a regra como reforço e tire o arquivo do diretório público.
  • Editar arquivos direto no servidor de produção: os editores deixam para trás backups terminados em ~ ou .swp. O guia de testes da OWASP também desaconselha editar arquivos no próprio servidor web. Edite localmente e envie as mudanças pelo seu deploy.
  • Copiar a pasta inteira do projeto para o diretório público: .env, .git e dados de teste vão junto. Sirva só a pasta de saída do build e defina exatamente o que é copiado.
  • Bloquear todo caminho com ponto e quebrar a renovação de certificados: o Let's Encrypt coloca o arquivo de verificação em /.well-known/acme-challenge/. Como no exemplo de Nginx acima, libere esse caminho primeiro.
  • Colocar segredos em variáveis VITE_ ou NEXT_PUBLIC_: elas são embutidas no JavaScript do build para qualquer um ler. Use-as só no código do lado do servidor e revogue qualquer chave que já tenha sido publicada assim.
  • Apagar o arquivo e parar por aí: se um buscador o indexou, ele pode continuar nos resultados. Confirme que a URL retorna 404 ou 410 e depois oculte-a temporariamente (cerca de seis meses) com a ferramenta Remoções do Google Search Console, enquanto um novo rastreamento a remove.

Um caso real: dados pessoais ocultos num relatório publicado

O Department of Health Care Finance (DHCF), que administra o Medicaid (cobertura pública de saúde para pessoas de baixa renda) em Washington, D.C., disse que dois relatórios estatísticos publicados no seu site de 2023 até julho de 2026 continham os dados pessoais de base como "campos ocultos". Os relatórios foram feitos para mostrar só números agregados, mas os arquivos ainda guardavam os números do Medicaid dos beneficiários, datas de nascimento e mais. A notificação ao Departamento de Saúde e Serviços Humanos dos EUA (HHS) informou 399.086 pessoas afetadas. O DHCF soube do problema em 21 de julho de 2026 e removeu os relatórios.

Não é um caso de arquivo de segredo esquecido, mas a raiz é a mesma:

  • Um arquivo num diretório público pode ser baixado por inteiro, não só a parte mostrada na tela
  • A informação que quem publica acha que "não está visível" é a mais fácil de passar despercebida numa revisão
  • Ela pode ficar publicada por anos antes que alguém perceba

Uma etapa que confere "o que de fato há dentro deste arquivo" antes de publicar evita tanto arquivos esquecidos quanto dados ocultos. O relato completo está em a exposição de dados do Medicaid em Washington, D.C. (em inglês).

O que este site faz por conta própria

A regra básica deste site é manter segredos — chaves, tokens, strings de conexão — fora tanto do diretório público quanto do repositório de código. Os artefatos de deploy contêm apenas assets públicos construídos; os segredos ficam como variáveis de ambiente do ambiente de execução, em um lugar que não é servido. O motivo: a classe de incidente deste artigo é o caso típico em que um único arquivo esquecido vaza tudo para qualquer um que solicite sua URL. Projetamos o posicionamento em si como controle de acesso e rodamos esta auditoria na mesma cadência do inventário de resposta a vulnerabilidades.

Leia a seguir

Fontes

  • IPA, "20 Checkpoints for Secure Website Operation and Management" (em japonês; arquivos que não devem ser públicos, cache de buscadores): ipa.go.jp
  • OWASP, "Web Security Testing Guide: Review Old Backup and Unreferenced Files for Sensitive Information" (backups .old, ~, .swp; não editar no próprio servidor): wstg.owasp.org
  • Apache HTTP Server 2.4, "Upgrading to 2.4 from 2.2" (AllowOverride tem padrão None) e "mod_autoindex" (Options +Indexes gera listagens): httpd.apache.org, httpd.apache.org
  • nginx, "ngx_http_core_module: location" (ordem de correspondência e ^~) e "ngx_http_autoindex_module" (autoindex tem padrão off): nginx.org, nginx.org
  • Let's Encrypt, "Challenge Types" (o HTTP-01 usa /.well-known/acme-challenge/): letsencrypt.org
  • Vite, "Env Variables and Modes" (variáveis VITE_ ficam expostas ao código do cliente): vite.dev
  • Next.js, "Environment Variables" (variáveis NEXT_PUBLIC_ são embutidas no JavaScript do navegador): nextjs.org
  • Ajuda do Google Search Console, "Removals tool" (a remoção temporária dura cerca de seis meses): support.google.com
  • District of Columbia DHCF, "Notice of Data Incident": dhcf.dc.gov; HIPAA Journal (número informado ao HHS): hipaajournal.com

FAQ

QPor que colocar arquivos em um diretório público é perigoso?
A

Qualquer coisa no diretório público da web (webroot — public/, public_html/ etc.) pode ser baixada por qualquer um que acesse sua URL. Um JSON de token/credenciais esquecido, um .env, um backup ou um arquivo de chave é recuperado antes de alguém notar, levando a dano imediato. O diretório público deve conter apenas coisas que é seguro serem públicas.

QSe eu achar um em um site, devo verificar os outros?
A

Sim. Se você produz sites em massa a partir de um template ou boilerplate compartilhado, o mesmo resquício normalmente é copiado para todos eles. Ache um e audite todos os sites e hosts de mesma origem.

QO que faço quando acho um?
A

1) Remova o arquivo do webroot para que retorne 404 pela URL. 2) Renove/revogue qualquer token ou chave que possa ter vazado (presuma que vazou). 3) Daqui em diante, mantenha segredos fora do webroot com permissão 600 (leitura só do dono). Faça os três como um conjunto.

QQuais arquivos nunca devem ficar num diretório web público?
A

Os suspeitos de sempre são arquivos de configuração como o .env, arquivos JSON de token ou credenciais, dumps de banco de dados (.sql), arquivos ZIP ou tar.gz do site inteiro, o diretório .git e backups feitos à mão ou pelo editor (.bak, .old, .orig, .swp, ou um nome terminado em ~). O guia de testes da OWASP explica que, se login.php for guardado como login.php.old, o servidor pode não executá-lo como código e devolver o código-fonte como texto puro.

QApaguei o arquivo, mas ele ainda aparece nos resultados de busca. O que faço?
A

Primeiro confirme que a URL retorna 404 ou 410, depois use a ferramenta Remoções do Google Search Console para ocultá-la temporariamente dos resultados. Segundo a página de ajuda do Google, uma remoção temporária dura cerca de seis meses e deve ser combinada com uma correção permanente, como apagar o arquivo. A IPA do Japão também recomenda pedir aos buscadores que removam cópias em cache. Revogue qualquer chave ou token que o arquivo continha, tenha ele saído dos resultados de busca ou não.

QPosso colocar segredos em variáveis de ambiente do frontend (VITE_ ou NEXT_PUBLIC_)?
A

Não. O Vite embute as variáveis que começam com VITE_, e o Next.js as que começam com NEXT_PUBLIC_, no JavaScript enviado ao navegador no momento do build. É o mesmo que colocar um arquivo no diretório público: qualquer um consegue ler. Mantenha chaves de API e outros segredos em variáveis usadas só pelo código do lado do servidor.