Kontrola citlivých souborů
Zjistěte, jestli váš web veřejně nevydává soubory, které na něj nepatří: repozitář .git, konfiguraci .env, zálohy databáze nebo logy. Vysvětlíme, jak nález ověřit a co s ním dělat.
Co kontrola ověřuje
Při nasazování webu se na server snadno dostanou soubory, které tam nepatří: celý adresář .git, soubor .env s heslem k databázi, zapomenutá záloha nebo log. Webový server je pak vydá každému, kdo zná jejich název. Roboti tyto adresy plošně zkoušejí na všech webech, takže spoléhat na to, že o souboru nikdo neví, nejde.
Nástroj se vašeho serveru zeptá na pevný seznam více než 30 běžných cest a u každé zjistí, jestli ji server vydá. Z každé odpovědi přečte nejvýše první 4 kB, aby poznal, jestli jde o skutečný soubor, nebo jen o běžnou stránku webu. Obsah neukládáme ani nezobrazujeme.
- Verzovací systémy –
/.git/HEAD,/.git/configa/.svn/entries. Z dostupného repozitáře lze stáhnout zdrojový kód i celou historii změn, často včetně hesel, která v ní kdysi byla. - Konfigurace a tajné klíče –
/.env,/.env.local,/.env.production,/config.php,/config.jsona záložní kopiewp-config.phps příponou.baknebo.old. - Zálohy a exporty –
/backup.sql,/database.sql,/db.sql,/backup.zip,/backup.tar.gza/.htaccess.bak. - Ladicí a provozní soubory –
/phpinfo.php,/info.php,/test.php,/debug.log,/error.log, stránka/server-statusa soubory/.htpasswda/web.config. - Další stopy po vývoji –
/package.json,/package-lock.json,/composer.json, adresáře/node_modules/,/vendor/a/.vscode/, systémové soubory/.DS_Storea/Thumbs.dba u WordPressu/xmlrpc.phpa/wp-admin/. - Standardní soubory –
/robots.txt,/sitemap.xmla/.well-known/security.txt. Ty naopak na webu mít dává smysl.
Jak číst výsledek
Kontrolujeme adresu, na které web skutečně běží. Když zadaná adresa přesměruje třeba z HTTP na HTTPS nebo na variantu s www, otestujeme cílový web. Všechny cesty zkoušíme od kořene domény.
Mnoho webů odpoví na jakoukoli neexistující adresu stavem 200 a úvodní stránkou. Proto se nespokojíme se stavovým kódem. Odpověď ve formátu HTML (text/html) nikdy nepovažujeme za hledaný soubor .env nebo zálohu. U každého typu cesty si navíc vyžádáme náhodnou adresu stejného tvaru (stejný adresář, přípona, tečka na začátku). Odpověď počítáme, jen když server náhodnou adresu odmítne (404, 410 nebo přesměrováním mimo web), nebo když na ni odpoví jinak než na hledanou cestu. Samotnou adresu, kterou některé weby v odpovědi zopakují, přitom nebereme v úvahu. Když server na náhodnou adresu odpoví chybou nebo omezením počtu požadavků, nález potvrdit nelze. Stránky, které server generuje, jako phpinfo(), /server-status nebo výpis adresáře, poznáme podle jejich typického obsahu.
- Veřejně dostupné – server cestu vydal a odpověď vypadá jako skutečný soubor nebo vygenerovaná stránka. Nález ověřte podle postupu níže.
- Nedostupné – server vrátil 404 nebo 410, přesměroval mimo váš web, nebo poslal jen běžnou stránku webu. U
config.phpto platí i tehdy, když skript existuje, ale server ho spustí a jeho zdrojový kód nevydá. - Přístup odepřen – server odpověděl 401 nebo 403. Obvykle jde o vaše pravidlo, které soubor chrání, ale stejně odpovídá i firewall, který blokuje naše požadavky.
- Neověřeno – server odpověděl chybou, omezením počtu požadavků (například 429) nebo přesměrováním, které nikam nevedlo, neodpověděl do 5 sekund, místo webu odpověděla ochrana proti robotům, nebo z odpovědi nešlo spolehlivě poznat, jestli soubor existuje. Neověřené zůstanou i cesty, na které už nezbyl čas, protože celá kontrola má časový limit. Takový výsledek neříká nic o tom, jestli je soubor na serveru. Když se to stane u většiny cest, upozorníme, že výsledek je neúplný.
- Dostupné, zvažte omezení – administrace WordPressu (
/wp-admin/) nebo rozhraní/xmlrpc.php. Jsou veřejná záměrně, nejde o únik souboru, ale roboti na nich zkoušejí hádat hesla. - Standardní soubory – u
robots.txt,sitemap.xmlasecurity.txtje nález naopak žádoucí. Přesměrování na jiný web, které RFC 9116 usecurity.txtdovoluje a které je běžné u map stránek na CDN, počítáme jako nález. Absence těchto souborů zabezpečení neoslabuje,security.txtale doporučujeme doplnit.
Cesta Odpověď serveru Výsledek
/.tunasec-nahodna-cesta 404, text/html (srovnání)
/.env 200, text/plain: DB_PASSWORD=… Veřejně dostupné
/sitemap.xml 200, text/html: úvodní stránka Nenalezeno
/.git/HEAD 403 Přístup odepřen (HTTP 403)
/backup.sql 429 Neověřeno (HTTP 429)
/wp-admin/ 302 → /wp-login.php, 200 Dostupné, zvažte omezení- Náhodná cesta ukazuje, jak server odpovídá na neexistující soubory stejného tvaru jako
/.env, tedy s tečkou na začátku a bez přípony. Tady vrátil 404. /.envvrátil 200 a obsah, který není stránkou HTML, zatímco náhodná adresa stejného tvaru vrátila 404. Nástroj ho proto označí jako veřejně dostupný./sitemap.xmlvrátil 200, ale jen úvodní stránku webu. Mapa stránek tedy na této adrese není, i když stavový kód říká opak./.git/HEADvrátil 403: server přístup odepřel. Odpověď 404 je o něco lepší, protože neprozradí, jestli adresář na serveru je./backup.sqlvrátil 429, server nás dočasně omezil. O záloze proto nevíme nic a je potřeba ji ověřit jinak, například příkazem z postupu níže.
Co dělat, když nástroj něco najde
Ověřte, co server opravdu vydává
Otevřete adresu v prohlížeči nebo spusťte
curl -s https://vase-firma.cz/.env | head -n 5. Pokud uvidíte hesla, klíče, příkazy SQL nebo u.git/HEADřádekref: refs/heads/main, soubor je opravdu veřejný. Stejným příkazem ověříte i cesty, které nástroj označil jako neověřené.Zablokujte přístup
Soubor z webového adresáře odstraňte, nebo přístup zakažte v konfiguraci serveru podle příkladu níže. Zálohy, exporty databáze a logy patří mimo adresář, který server vydává. Ladicí skripty jako
phpinfo.phpsmažte. Potom kontrolu spusťte znovu.Vyměňte všechna tajemství, která byla dostupná
Smazání souboru nestačí, kopii už mohl někdo stáhnout. Změňte hesla k databázi, API klíče, přístupy k SMTP a cloudu i aplikační klíče jako
APP_KEYneboSECRET_KEY. U dostupného.gitpočítejte s tím, že útočník má zdrojový kód i všechno, co kdy bylo v historii.Zjistěte, jestli si soubor někdo stáhl
V přístupových logech hledejte požadavky na danou cestu s odpovědí 200, například na
/.envnebo/.git/. Pokud logy sahají jen pár dní zpět, to, že v nich nic není, nic nedokazuje. Pokud mohlo dojít k úniku osobních údajů, posuďte, jestli nemusíte incident do 72 hodin od zjištění ohlásit Úřadu pro ochranu osobních údajů.Upravte nasazování, aby se chyba neopakovala
Na server nahrávejte jen výsledek sestavení, ne pracovní kopii repozitáře: artefakt z CI nebo
rsyncs vyloučením.gita.env. Kořen webu nastavte na podadresář typupublic/, aby konfigurace a závislosti ležely mimo něj. Tajemství, které se dostalo do commitu, odstraňte z historie nástrojemgit filter-repo, ale až po výměně klíčů, ne místo ní.
# nginx – uvnitř bloku server { }, před ostatními regulárními location
# skryté soubory a adresáře (.git, .env, .htpasswd) kromě .well-known
location ~ /\.(?!well-known/) {
return 404;
}
# zálohy, exporty databáze a logy
location ~* \.(sql|bak|old|log)$ {
return 404;
}
# Apache 2.4 – konfigurace webu nebo .htaccess
RedirectMatch 404 "/\.(?!well-known/)"
<FilesMatch "\.(sql|bak|old|log)$">
Require all denied
</FilesMatch>- Regulární bloky
locationvyhodnocuje nginx v pořadí, v jakém jsou zapsané, a použije první, který cestě odpovídá. Pravidla proto dejte před ostatní regulární bloky, například před zpracování PHP. - Výjimka pro
.well-knownje nutná, jinak zablokujete isecurity.txta ověřování certifikátů Let’s Encrypt. return 404neprozradí, že soubor existuje.deny allv nginx neboRequire all deniedv Apache vrací 403, což chrání stejně, jen existenci souboru potvrdí.- Stránku
/server-statusv Apache omezte direktivouRequire localneboRequire ips adresami správců. Blokování v konfiguraci je pojistka: zálohy a logy na webový server vůbec nepatří.
Co kontrola neříká
- Zkoušíme jen pevný seznam cest. Soubory s jinými názvy, například
zaloha-2025.zipnebo.env.bak, nenajdeme. Web neprocházíme ani neodhadujeme další názvy. - Testujeme jen kořen jedné domény. Pokud zadáte adresu s cestou, cestu ignorujeme. Jiné subdomény, například
admin.vase-firma.cz, zkontrolujte zvlášť. - Nález je založený na prvních 4 kB odpovědi. Nevíme proto, jaké tajné údaje soubor obsahuje, a soubor, který server posílá jako HTML (
text/html), za nález nepovažujeme. - Skript bez rozpoznatelného obsahu, jako je
test.php, umíme spolehlivě posoudit jen na webech, které na neexistující adresy odpovídají 404 nebo 410. Na ostatních webech ho označíme jako neověřený, pokud jeho odpověď není stejná jako odpověď na náhodnou adresu. - Když server odpoví chybou, nestihne odpovědět do 5 sekund nebo naše požadavky zablokuje firewall či ochrana proti robotům (například od Vercelu nebo Cloudflaru), cestu označíme jako neověřenou nebo s odepřeným přístupem. Celá kontrola má navíc limit zhruba 25 sekund a cesty, na které nezbude čas, označíme také jako neověřené. Neznamená to, že soubor na serveru není.
- Žádný nález neznamená bezpečný web. Zranitelnosti v aplikaci, přihlašování nebo API odhalí až penetrační test.
- Připojujeme se jen k veřejným adresám, a to i po přesměrování. Výsledek ani obsah odpovědí neukládáme a z jedné IP adresy lze spustit nejvýše pět kontrol za minutu.
Časté otázky
Proč nástroj u /wp-admin/ doporučuje omezení, když web funguje normálně?
Na WordPressu tato adresa přesměruje na přihlašovací stránku, takže je dostupná záměrně a nejde o únik souboru. Roboti na ní ale zkoušejí hádat hesla. Zapněte vícefaktorové ověření, omezte počet pokusů o přihlášení, a pokud administraci používá jen pár lidí, povolte ji jen z vybraných IP adres. Rozhraní /xmlrpc.php vypněte, pokud ho nepoužívá mobilní aplikace nebo jiná služba.
Stačí dostupný soubor smazat?
Ne. Smazáním zabráníte dalšímu stažení, ale kopie, které už někdo má, tím nezmizí. Hesla a klíče, které soubor obsahoval, považujte za vyzrazené a vyměňte je. Teprve potom má smysl čistit historii repozitáře.
Kontrola nic nenašla. Je web v pořádku?
Znamená to jen, že server žádnou z testovaných cest nevydal. Zkontrolujte, jestli některé cesty nejsou neověřené nebo s odepřeným přístupem kvůli firewallu. Soubory s jinými názvy, aplikace v podadresářích ani zranitelnosti v samotné aplikaci tato kontrola nepokrývá.
Uvidí kontrolu správce serveru?
Ano. Do přístupového logu se zapíše zhruba 60 požadavků GET s identifikací (User-Agent) TunaSec-Security-Scanner/1.0, včetně náhodných adres obsahujících tunasec-. Najednou jich posíláme nejvýše deset a z každé odpovědi čteme jen začátek, takže běžný web kontrola nezatíží. Kontrolujte jen weby, které spravujete, nebo k tomu máte svolení.
Nevadí, že robots.txt ukazuje, kde je administrace?
robots.txt je jen doporučení pro vyhledávače, ne ochrana. Je veřejný a útočníci ho čtou mezi prvními. Nevypisujte do něj adresy, které mají zůstat skryté. Co nemá být veřejné, chraňte přihlášením, nebo to na server vůbec nedávejte.
K čemu je security.txt?
Soubor /.well-known/security.txt podle standardu RFC 9116 říká, kam hlásit nalezené zranitelnosti. Povinná jsou pole Contact a Expires. Díky němu se upozornění od bezpečnostního výzkumníka dostane ke správnému člověku a neztratí se v obecné schránce.
Chcete vědět, co dalšího útočník na webu najde?
Kontrola souborů pokrývá jen nejčastější chyby při nasazení. Napište nám, o jaký web jde, a probereme, jak ho prověřit důkladněji.
Napsat námPři penetračním testu hledáme i soubory s jinými názvy a slabá místa v přihlašování, API a infrastruktuře a ověřujeme, kam by se útočník reálně dostal.
Penetrační testování