Ukratko: .env datoteku štitite tako da uopće ne leži u javno dostupnom direktoriju: webroot pokazuje na poddirektorij poput public/, a konfiguracija leži jednu razinu iznad. Uz to web-poslužitelj blokira sve datoteke s točkom na početku, datoteka je čitljiva samo vlasniku i PHP procesu i nikad ne pripada u Git repozitorij. Nakon provale svi pristupni podaci u njoj smatraju se poznatima i zamjenjuju se.
Datoteka s ključevima kuće
Moderni PHP projekti svoje tajne rado pohranjuju u datoteku naziva .env: lozinka baze podataka, pristup poslužitelju e-pošte, API ključevi za usluge plaćanja i dostave, ključ kojim aplikacija potpisuje kolačiće. Frameworci poput Laravela i Symfonyja koriste taj uzorak, a mnoge vlastite izvedbe su ga preuzele.
Ideja je dobra: konfiguracija i kod su odvojeni, a svako okruženje dobiva vlastite vrijednosti. Opasno postaje kad datoteka završi u pogrešnom direktoriju. Ako leži u webrootu, a web-poslužitelj je ne blokira, dovoljan je jedan poziv u pregledniku da se odjednom pročitaju svi pristupi.
Tome se pridružuju varijante s drugim nazivima: .env.local, .env.production, config.local.php ili datoteke s pristupnim podacima za usluge pohrane. Ono što je ovdje opisano za .env vrijedi za sve datoteke u kojima stoje tajne.
Takve datoteke automatizirani skeneri neprestano traže. To nije specijalnost pojedinih napadača, nego osnovna buka na internetu, slično masovnim skeniranjima nezakrpanih PHP verzija.
Gdje bi trebala ležati .env datoteka
Najučinkovitija mjera je strukturalna: web-poslužitelj smije isporučivati samo mapu koja doista treba biti javna. U Laravelu i Symfonyju to je mapa public/. Sve ostalo, dakle kod, konfiguracija, zapisnici i .env, leži iznad nje i preko HTTP-a uopće se ne može adresirati.
/srv/www/shop/
├── .env ← nedostupno
├── config/
├── src/
├── vendor/
└── public/ ← jedini webroot
├── index.php
└── assets/
U praksi webroot ipak često pokazuje na sam direktorij projekta, primjerice jer to zadaje hosting panel ili jer pri selidbi putanja nije prilagođena. Zato u konfiguraciji web-poslužitelja ili u panelu provjerite kamo pokazuje root odnosno DocumentRoot.
Zaštita .env datoteke: blokada u web-poslužitelju kao druga linija
Ako se webroot ne može promijeniti ili želite dodatnu zaštitu, blokirajte skrivene datoteke u web-poslužitelju. Mapa .well-known pritom mora ostati dostupna jer se među ostalim koristi za izdavanje certifikata.
# Blokirati sve datoteke i mape s točkom na početku, osim .well-known
location ~ /\.(?!well-known/) {
deny all;
return 404;
}
# Blokirati datoteke s točkom na početku
<FilesMatch "^\.">
Require all denied
</FilesMatch>
Odgovor 404 umjesto 403 ne otkriva da datoteka postoji. Djeluje li blokada, provjerite izvana:
# Očekuje se: 403 ili 404, nikada 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
Posljednja dva retka nisu slučajna: kopije poput .env.bak ili .env.old nastaju pri radovima održavanja i često se zaborave. Više o takvim ostacima stoji u članku Sigurnosne kopije u webrootu.
Prava, Git i postupanje s kopijama
I izvan webroota vrijedi načelo najmanjih prava. Dokazana podjela:
- Vlasnik je korisnik za isporuku (deploy), a ne PHP proces.
- Grupa je grupa PHP-FPM poola, koja smije samo čitati; prava
640. - Bez pristupa pisanju za PHP proces. Aplikacija ne mora moći mijenjati vlastite pristupne podatke.
- Bez stvarnih vrijednosti u repozitoriju: u repozitorij se unosi samo
.env.examples rezerviranim mjestima, a stvarna datoteka stoji u.gitignore. - Odvojene vrijednosti po okruženju: razvoj, staging i produkcija koriste različite pristupe kako curenje u testnom okruženju ne bi otvorilo produkciju.
chown deploy:shop-php /srv/www/shop/.env
chmod 640 /srv/www/shop/.env
# Provjeriti je li datoteka ikada unesena u repozitorij
git log --all --oneline -- .env
Pazite i na stranice s pogreškama. Frameworci u debug načinu ponekad prikazuju varijable okruženja i konfiguracijske vrijednosti; na produkcijskom sustavu taj način mora biti isključen. Provjerite to nakon svake isporuke, jer pogrešna vrijednost u samoj .env može ga ponovno uključiti.
Ako zadnja naredba vrati pogotke, pristupni podaci nalaze se u Git povijesti i smatraju se otkrivenima, čak i ako datoteke danas nema. Zašto je to osobito ozbiljno kad direktorij .git leži na poslužitelju, opisuje Javni .git direktorij: podcijenjeno curenje podataka. Osnove o pravima objašnjava vodič Prava datoteka na web-poslužitelju.
Testne datoteke s phpinfo() prikazuju varijable okruženja. Tko tajne predaje kao varijable okruženja, odaje ih zaboravljenom testnom datotekom. Pozadina stoji u članku phpinfo() datoteke: zašto moraju nestati.
Nakon provale: zamijeniti pristupne podatke
Nijedna blokada ne štiti od napadača koji već izvršava kod na poslužitelju. PHP proces mora moći čitati svoju konfiguraciju, pa to može i ubačeni kod u istom procesu. Nakon PHP2Shella stoga vrijedi: ako se provala ne može isključiti, svi pristupni podaci na poslužitelju tretiraju se kao poznati.
Uredna zamjena obuhvaća lozinke baza podataka, pristupe e-pošti i SMTP-u, API ključeve vanjskih usluga, ključeve za potpis aplikacije i pristupe uslugama pohrane. Redoslijed i trenutak trebaju biti planirani: tko najprije zamijeni, a tek zatim očisti poslužitelj, napadaču možda odmah preda i nove vrijednosti.
Štetu od curenja ograničavate već unaprijed tako da svaka tajna smije samo onoliko koliko je nužno. Korisnik baze podataka web-stranice ne treba prava na druge baze. API ključevi vanjskih usluga kod mnogih se pružatelja mogu ograničiti na pojedine funkcije ili adrese pošiljatelja, primjerice stvaranje pošiljki, ali ne i pokretanje isplata. I svaka aplikacija dobiva vlastite pristupe, umjesto da više web-stranica dijeli isti račun e-pošte ili isti ključ. Tada curenje pogađa jasno omeđeno područje, a zamjena ostaje pregledna.
U okruženjima containera .env datoteka ne pripada ni u image ni u javno dostupan registry. Isključite je pomoću .dockerignore i tajne predajte tek za vrijeme rada mehanizmima platforme.
Dugoročno vrijedi pogledati središnja spremišta tajni, kakva preporučuje OWASP: tajne na jednom mjestu, sa zapisnikom pristupa, redovitom zamjenom i što kraćom valjanošću.
Kako PHP SOS konkretno pomaže?
- Izvana provjeravamo jesu li konfiguracijske datoteke, kopije i skrivene datoteke Vaših web-stranica dostupne.
- Webroot, blokade web-poslužitelja i prava datoteka postavljamo tako da tajne više nisu dostupne preko HTTP-a.
- Provjeravamo repozitorije i isporuke u potrazi za unesenim pristupnim podacima.
- Nakon incidenta planiramo i pratimo zamjenu svih pogođenih pristupa ispravnim redoslijedom.
Ovi radovi dio su našeg ojačavanja poslužitelja za PHP web-poslužitelje.
Česta pitanja
Je li .env datoteka u webrootu automatski javna?
Ne automatski, ali često. Je li dostupna, ovisi o konfiguraciji web-poslužitelja. Mnoge zadane konfiguracije štite samo .htaccess datoteke, a ne druge datoteke s točkom na početku. Test pomoću curl-a daje jasnoću.
Jesu li varijable okruženja sigurnije od .env datoteke?
Ne u načelu. OWASP upozorava da su varijable okruženja čitljive svim procesima korisnika i da se mogu pojaviti u zapisnicima ili ispisima memorije. Ipak izbjegavaju datoteku u webrootu. Bolja su središnja spremišta tajni, gdje ih okruženje podržava.
Što učiniti ako je .env datoteka bila dostupna?
Sve pristupne podatke u njoj smatrati poznatima i zamijeniti ih: baza podataka, e-pošta, API-ji, usluge plaćanja, ključevi aplikacije. Zatim u pristupnim zapisnicima provjeriti je li datoteka dohvaćena, a kod osobnih podataka uključiti službenika za zaštitu podataka.
Pripada li .env datoteka u Git repozitorij?
Ne. U repozitorij najviše pripada predložak bez stvarnih vrijednosti, primjerice .env.example. Stvarna datoteka isključuje se pomoću .gitignore i na poslužitelju se stavlja na raspolaganje odvojeno.
Može li phpinfo() otkriti pristupne podatke?
Da. phpinfo() među ostalim prikazuje varijable okruženja i poslužiteljske varijable. Ako su tamo tajne, ispisuju se zajedno s njima. Testne datoteke s phpinfo() zato nikad ne pripadaju na dostupan sustav.