Stručně: Soubor .env chráníte tak, že vůbec neleží ve veřejně dostupném adresáři: webroot ukazuje na podsložku jako public/, konfigurace leží o úroveň výš. Webserver navíc blokuje všechny soubory s tečkou na začátku, soubor je čitelný jen pro vlastníka a proces PHP a nikdy nepatří do repozitáře Git. Po průniku se všechny přístupové údaje v něm považují za známé a vyměňují se.
Soubor s klíči od domu
Moderní projekty v PHP rády ukládají svá tajemství do souboru s názvem .env: heslo k databázi, přístup k poštovnímu serveru, klíče API pro platební a dopravní služby, klíč, kterým aplikace podepisuje cookies. Frameworky jako Laravel a Symfony tento vzor používají a mnoho vlastních vývojů jej převzalo.
Myšlenka je dobrá: konfigurace a kód jsou odděleny a každé prostředí dostane vlastní hodnoty. Nebezpečné to začne být, když soubor skončí ve špatném adresáři. Pokud leží ve webrootu a webserver ho neblokuje, stačí jediné zavolání v prohlížeči a přečtou se všechny přístupy najednou.
K tomu přistupují varianty s jinými názvy: .env.local, .env.production, config.local.php nebo soubory s přístupovými údaji k úložným službám. Co je zde popsáno pro .env, platí pro všechny soubory, ve kterých jsou tajemství.
Takové soubory automatizované skenery neustále vyhledávají. Není to specialita jednotlivých útočníků, ale základní šum internetu, podobně jako hromadné skenování nezáplatovaných verzí PHP.
Kde by měl soubor .env ležet
Nejúčinnějším opatřením je strukturální: webserver smí doručovat jen složku, která má být skutečně veřejná. V Laravelu a Symfony je to složka public/. Vše ostatní, tedy kód, konfigurace, logy a .env, leží nad ní a přes HTTP není vůbec adresovatelné.
/srv/www/shop/
├── .env ← nedostupné
├── config/
├── src/
├── vendor/
└── public/ ← jediný webroot
├── index.php
└── assets/
V praxi ukazuje webroot přesto často na samotný adresář projektu, například proto, že to vyžaduje panel hostingu, nebo proto, že se při přesunu neupravila cesta. Zkontrolujte proto v konfiguraci webserveru nebo v panelu, kam ukazuje root, resp. DocumentRoot.
Ochrana souboru .env: blokování ve webserveru jako druhá linie
Pokud webroot nelze změnit, nebo chcete další zabezpečení, zablokujte skryté soubory ve webserveru. Složka .well-known přitom musí zůstat dostupná, protože se mimo jiné používá k vydávání certifikátů.
# Zablokovat všechny soubory a složky s tečkou na začátku, kromě .well-known
location ~ /\.(?!well-known/) {
deny all;
return 404;
}
# Zablokovat soubory s tečkou na začátku
<FilesMatch "^\.">
Require all denied
</FilesMatch>
Odpověď 404 místo 403 neprozradí, že soubor existuje. Zda blokování funguje, ověřte zvenčí:
# Očekáváno: 403 nebo 404, nikdy 200
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env.example
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env.bak
Poslední dva řádky nejsou náhoda: kopie jako .env.bak nebo .env.old vznikají při údržbě a často se zapomenou. Více o takových pozůstatcích najdete v článku Záložní soubory ve webrootu.
Práva, Git a zacházení s kopiemi
I mimo webroot platí zásada nejmenších oprávnění. Osvědčené rozdělení:
- Vlastníkem je uživatel pro nasazování, ne proces PHP.
- Skupinou je skupina poolu PHP-FPM, která smí jen číst; práva
640. - Žádný zápis pro proces PHP. Aplikace nemusí umět měnit vlastní přístupové údaje.
- Žádné skutečné hodnoty v repozitáři: Do repozitáře se vkládá jen
.env.examplese zástupnými hodnotami, skutečný soubor je v.gitignore. - Oddělené hodnoty pro každé prostředí: Vývoj, staging a produkce používají různé přístupy, aby únik v testovacím prostředí neotevřel produkci.
chown deploy:shop-php /srv/www/shop/.env
chmod 640 /srv/www/shop/.env
# Zkontrolovat, zda byl soubor někdy vložen do repozitáře
git log --all --oneline -- .env
Věnujte pozornost také chybovým stránkám. Frameworky v ladicím režimu někdy zobrazují proměnné prostředí a hodnoty konfigurace; na produkčním systému musí být tento režim vypnutý. Kontrolujte to po každém nasazení, protože chybná hodnota v samotném .env ho může znovu zapnout.
Pokud poslední příkaz vrátí nálezy, jsou přístupové údaje v historii Gitu a považují se za odhalené, i když soubor dnes chybí. Proč je to obzvlášť citlivé, když složka .git leží na serveru, popisuje článek Veřejná složka .git: podceňovaný únik dat. Základy o právech vysvětluje příručka Oprávnění k souborům na webserveru.
Testovací soubory s phpinfo() zobrazují proměnné prostředí. Kdo předává tajemství jako proměnné prostředí, prozradí je zapomenutým testovacím souborem. Souvislosti najdete v článku Soubory phpinfo(): proč musí zmizet.
Po průniku: výměna přístupových údajů
Žádné blokování nechrání před útočníkem, který už spouští kód na serveru. Proces PHP musí umět číst svou konfiguraci, takže to umí i vložený kód ve stejném procesu. Po PHP2Shell proto platí: pokud nelze průnik vyloučit, je třeba všechny přístupové údaje na serveru považovat za známé.
Uspořádaná výměna zahrnuje hesla k databázi, přístupy k poště a SMTP, klíče API externích služeb, podpisové klíče aplikace a přístupy k úložným službám. Pořadí a čas by měly být naplánovány: kdo nejdřív vymění a poté server vyčistí, může útočníkovi nové hodnoty rovnou prozradit.
Škodu z úniku omezíte už předem tím, že každé tajemství smí jen tolik, kolik je nutné. Databázový uživatel webu nepotřebuje práva k jiným databázím. Klíče API externích služeb lze u mnoha poskytovatelů omezit na jednotlivé funkce nebo adresy odesílatele, například zakládání zásilek, ale ne zadávání výplat. A každá aplikace dostane vlastní přístupy, místo aby několik webů sdílelo stejný poštovní účet nebo stejný klíč. Únik pak zasáhne jasně vymezenou oblast a výměna zůstane přehledná.
V prostředích kontejnerů soubor .env nepatří ani do image, ani do veřejně dostupného registru. Vylučte ho pomocí .dockerignore a tajemství předávejte až za běhu pomocí mechanismů platformy.
Z dlouhodobého hlediska se vyplatí podívat se na centrální úložiště tajemství, jak je doporučuje OWASP: tajemství na jednom místě, s protokolem přístupů, pravidelnou výměnou a pokud možno co nejkratší platností.
Jak konkrétně pomáhá PHP SOS?
- Zvenčí zkontrolujeme, zda jsou konfigurační soubory, kopie a skryté soubory vašich webů dostupné.
- Webroot, blokování ve webserveru a práva k souborům upravíme tak, aby tajemství nebyla přes HTTP dostupná.
- Zkontrolujeme repozitáře a nasazení na vložené přístupové údaje.
- Po incidentu naplánujeme a doprovodíme výměnu všech dotčených přístupů ve správném pořadí.
Tyto práce jsou součástí našeho hardeningu serveru pro webservery s PHP.
Časté dotazy
Je soubor .env ve webrootu automaticky veřejný?
Ne automaticky, ale často. Zda je dostupný, závisí na konfiguraci webserveru. Mnoho výchozích konfigurací chrání jen soubory .htaccess, ne jiné soubory s tečkou na začátku. Jasno udělá test pomocí curl.
Jsou proměnné prostředí bezpečnější než soubor .env?
Ne zásadně. OWASP upozorňuje, že proměnné prostředí může číst každý proces uživatele a mohou se objevit v lozích nebo výpisech paměti. Vyhnete se tím ale souboru ve webrootu. Lepší jsou centrální úložiště tajemství, kde je prostředí podporuje.
Co dělat, když byl soubor .env dostupný?
Všechny v něm obsažené přístupové údaje považujte za známé a vyměňte je: databáze, pošta, API, platební služby, klíče aplikace. Poté v přístupových lozích zkontrolujte, zda byl soubor stažen, a při osobních údajích přizvěte pověřence pro ochranu osobních údajů.
Patří soubor .env do repozitáře Git?
Ne. Do repozitáře patří nanejvýš šablona bez skutečných hodnot, například .env.example. Skutečný soubor se vyloučí přes .gitignore a na server se dodává odděleně.
Může phpinfo() prozradit přístupové údaje?
Ano. phpinfo() mimo jiné zobrazuje proměnné prostředí a proměnné serveru. Pokud jsou tam tajemství, vypíšou se také. Testovací soubory s phpinfo() proto nikdy nepatří na dostupný systém.