Pe scurt: Un fișier .env îl protejați făcând ca el să nu se afle deloc în directorul accesibil public: webroot-ul indică un subdirector precum public/, iar configurarea se află cu un nivel mai sus. În plus, serverul web blochează toate fișierele cu punct la început, fișierul este lizibil doar pentru proprietar și procesul PHP și nu aparține niciodată în depozitul Git. După o intruziune, toate datele de acces din el se consideră cunoscute și sunt înlocuite.
Fișierul cu cheile casei
Proiectele PHP moderne își depun cu plăcere secretele într-un fișier numit .env: parola bazei de date, accesul la serverul de e-mail, cheile API pentru servicii de plată și expediere, cheia cu care aplicația semnează cookie-urile. Framework-uri precum Laravel și Symfony folosesc acest tipar, iar multe dezvoltări proprii l-au preluat.
Ideea este bună: configurarea și codul sunt separate, iar fiecare mediu primește valori proprii. Devine periculos când fișierul ajunge în directorul greșit. Dacă se află în webroot și serverul web nu îl blochează, este suficient un singur apel în browser pentru a citi toate accesele deodată.
Se adaugă variante cu alte nume: .env.local, .env.production, config.local.php sau fișiere cu date de acces la servicii de stocare. Ce este descris aici pentru .env se aplică tuturor fișierelor în care se află secrete.
Astfel de fișiere sunt căutate continuu de scannere automate. Nu este o specialitate a unor atacatori individuali, ci zgomot de fond al internetului, asemănător scanărilor în masă după versiuni PHP nepatch-uite.
Unde ar trebui să se afle fișierul .env
Cea mai eficientă măsură este structurală: serverul web are voie să livreze doar directorul care chiar trebuie să fie public. În Laravel și Symfony acesta este directorul public/. Tot restul, adică codul, configurarea, jurnalele și .env, se află deasupra lui și nu poate fi deloc adresat prin HTTP.
/srv/www/shop/
├── .env ← inaccesibil
├── config/
├── src/
├── vendor/
└── public/ ← unicul webroot
├── index.php
└── assets/
În practică, webroot-ul indică totuși adesea chiar directorul proiectului, de exemplu pentru că un panou de hosting îl impune astfel sau pentru că la mutare o cale nu a fost ajustată. Verificați de aceea în configurarea serverului web sau în panou unde indică root, respectiv DocumentRoot.
Protejarea fișierului .env: blocarea în serverul web ca a doua linie
Dacă webroot-ul nu poate fi schimbat sau doriți o securizare suplimentară, blocați fișierele ascunse în serverul web. Directorul .well-known trebuie să rămână accesibil, deoarece este folosit, printre altele, pentru emiterea certificatelor.
# Blocați toate fișierele și directoarele cu punct la început, cu excepția .well-known
location ~ /\.(?!well-known/) {
deny all;
return 404;
}
# Blocați fișierele cu punct la început
<FilesMatch "^\.">
Require all denied
</FilesMatch>
Un răspuns 404 în loc de 403 nu trădează că fișierul există. Dacă blocarea funcționează, verificați din exterior:
# Așteptat: 403 sau 404, niciodată 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
Ultimele două rânduri nu sunt întâmplătoare: copii precum .env.bak sau .env.old apar la lucrări de mentenanță și sunt adesea uitate. Mai multe despre asemenea rămășițe se găsesc în Fișiere de backup în webroot.
Drepturi, Git și tratarea copiilor
Și în afara webroot-ului se aplică principiul drepturilor minime. O împărțire dovedită:
- Proprietar este utilizatorul de deploy, nu procesul PHP.
- Grupul este grupul pool-ului PHP-FPM, care are voie doar să citească; drepturi
640. - Fără acces de scriere pentru procesul PHP. O aplicație nu trebuie să își poată modifica propriile date de acces.
- Fără valori reale în depozit: Doar
.env.examplecu substituenți este inclus în depozit, fișierul real se află în.gitignore. - Valori separate pe mediu: Dezvoltarea, staging-ul și producția folosesc accese diferite, pentru ca o scurgere dintr-un mediu de test să nu deschidă producția.
chown deploy:shop-php /srv/www/shop/.env
chmod 640 /srv/www/shop/.env
# Verificați dacă fișierul a fost vreodată inclus în depozit
git log --all --oneline -- .env
Fiți atenți și la paginile de eroare. Framework-urile afișează în modul de depanare uneori variabile de mediu și valori de configurare; pe un sistem de producție acest mod trebuie să fie dezactivat. Verificați acest lucru după fiecare deployment, deoarece o valoare greșită chiar în .env îl poate reactiva.
Dacă ultima comandă returnează rezultate, datele de acces se află în istoricul Git și se consideră expuse, chiar dacă fișierul lipsește astăzi. De ce este deosebit de delicat acest lucru dacă directorul .git se află pe server descrie Director .git public: o scurgere de date subestimată. Aspecte fundamentale despre drepturi explică ghidul Drepturile de fișiere pe serverul web.
Fișierele de test cu phpinfo() afișează variabile de mediu. Cine transmite secrete ca variabile de mediu le trădează printr-un fișier de test uitat. Context găsiți în Fișiere phpinfo(): de ce trebuie să dispară.
După o intruziune: înlocuirea datelor de acces
Nicio blocare nu protejează împotriva unui atacator care execută deja cod pe server. Un proces PHP trebuie să își poată citi configurarea, deci poate face asta și codul introdus pe ascuns în același proces. După PHP2Shell se aplică de aceea: dacă o intruziune nu poate fi exclusă, toate datele de acces de pe server trebuie tratate ca fiind cunoscute.
O înlocuire ordonată cuprinde parolele bazelor de date, accesele de e-mail și SMTP, cheile API ale serviciilor externe, cheile de semnare ale aplicației și accesele la servicii de stocare. Ordinea și momentul ar trebui planificate: cine înlocuiește mai întâi și curăță apoi serverul îi dă probabil atacatorului imediat și valorile noi.
Paguba unei scurgeri o limitați încă dinainte, făcând ca fiecare secret să aibă voie doar cât este necesar. Utilizatorul bazei de date al site-ului nu are nevoie de drepturi asupra altor baze de date. Cheile API ale serviciilor externe pot fi restricționate, la mulți furnizori, la anumite funcții sau adrese de expeditor, de exemplu crearea de expedieri, dar nu inițierea de plăți. Și fiecare aplicație primește accese proprii, în loc ca mai multe site-uri să împartă același cont de e-mail sau aceeași cheie. Atunci o scurgere privește un domeniu clar delimitat, iar înlocuirea rămâne ușor de urmărit.
În mediile cu containere, fișierul .env nu aparține nici în imagine, nici într-un registru accesibil public. Excludeți-l prin .dockerignore și transmiteți secretele abia la rulare, prin mecanismele platformei.
Pe termen lung merită privirea către depozitele centrale de secrete, așa cum le recomandă OWASP: secrete într-un singur loc, cu jurnal de acces, înlocuire regulată și valabilitate cât mai scurtă.
Cum ajută PHP SOS concret?
- Verificăm din exterior dacă fișierele de configurare, copiile și fișierele ascunse ale site-urilor dumneavoastră pot fi accesate.
- Restructurăm webroot-ul, blocările din serverul web și drepturile de fișiere astfel încât secretele să nu mai fie accesibile prin HTTP.
- Verificăm depozitele și deployment-urile pentru date de acces incluse în cod.
- După un incident planificăm și însoțim înlocuirea tuturor accesărilor afectate, în ordinea corectă.
Aceste lucrări fac parte din întărirea serverului pentru servere web PHP oferită de noi.
Întrebări frecvente
Este un fișier .env din webroot public în mod automat?
Nu automat, dar adesea. Dacă poate fi accesat depinde de configurarea serverului web. Multe configurări implicite protejează doar fișierele .htaccess, nu alte fișiere cu punct la început. Un test cu curl aduce claritate.
Sunt variabilele de mediu mai sigure decât un fișier .env?
Nu în mod fundamental. OWASP atrage atenția că variabilele de mediu pot fi citite de toate procesele utilizatorului și pot apărea în jurnale sau în dump-uri de memorie. Evită însă un fișier în webroot. Mai bune sunt depozitele centrale de secrete, acolo unde mediul le acceptă.
Ce fac dacă fișierul .env a fost accesibil?
Considerați toate datele de acces conținute drept cunoscute și înlocuiți-le: baza de date, e-mail, API-uri, servicii de plată, chei ale aplicației. Apoi verificați în jurnalele de acces dacă fișierul a fost accesat și, în cazul datelor cu caracter personal, implicați responsabilul cu protecția datelor.
Aparține fișierul .env în depozitul Git?
Nu. În depozit aparține cel mult un șablon fără valori reale, de exemplu .env.example. Fișierul real este exclus prin .gitignore și furnizat separat pe server.
Poate phpinfo() să trădeze date de acces?
Da. phpinfo() afișează, printre altele, variabilele de mediu și variabilele serverului. Dacă secretele se află acolo, sunt afișate odată cu ele. Fișierele de test cu phpinfo() nu aparțin de aceea niciodată pe un sistem accesibil.