Na kratko: Pri varnosti nalaganja v PHP ne odloča posamezno preverjanje, ampak kombinacija: tip datoteke preverite na strežniku, datoteke preimenujte, shranjujte zunaj korena spleta in v mapi za nalaganje ne dovolite izvajanja skript. Nepreverjen obrazec za nalaganje je ena klasičnih poti, po kateri napadalci prinesejo stranska vrata na spletni strežnik.
Zakaj so obrazci za nalaganje priljubljen vstopni vhod
Vsak obrazec, ki sprejema datoteke, na vaš strežnik zapisuje tuje podatke. Sem sodijo obrazci za prijave, portali za stranke, galerije slik, podporna območja in številne razširitve CMS-jev in trgovin. Če napadalcu uspe tam odložiti datoteko, ki jo spletni strežnik nato izvede kot PHP, ima trajna stranska vrata.
Za vodstvo to pomeni: na videz neškodljivo nalaganje življenjepisov lahko v najslabšem primeru vodi do prevzema celotnega spletnega strežnika. Poleg tega so v mapah za nalaganje pogosto osebni podatki, ki so ob napačni konfiguraciji javno dosegljivi.
Za skrbnike in razvijalce to pomeni: koda aplikacije in konfiguracija strežnika morata ustrezati druga drugi. Šibkost na eni ravni pogosto ujame druga, če sta obe čisto izvedeni. Kako najdete že vnesene datoteke, opisuje vodnik Prepoznavanje in odstranitev webshellov.
Osnovna pravila za varnost nalaganja v PHP
Naslednja pravila ustrezajo priporočilom OWASP Cheat Sheets in so se obnesla v delovanju:
- Seznam dovoljenih namesto seznama prepovedanih: Sprejmite samo izrecno dovoljene tipe datotek, na primer PDF, JPG in PNG. Sezname prepovedanih posameznih končnic je mogoče zaobiti z različicami in dvojnimi končnicami.
- Preverjajte vsebino, ne samo končnice: Dejanski tip ugotovite na strežniku s
finfo. Tip MIME v$_FILESje navedba pošiljatelja in ni zaupanja vreden. - Novo ime datoteke: Izvirnega imena nikoli ne uporabite kot imena datoteke. Ustvarite naključno ime in dodajte končnico s seznama dovoljenih.
- Shranjevanje zunaj korena spleta: Datoteke shranite tako, da niso neposredno dosegljive prek URL. Dostava poteka prek skripte s preverjanjem pooblastil.
- Omejite velikost: V aplikaciji, v PHP in v spletnem strežniku.
- Brez izvajanja: Če morajo nalaganja vendarle ležati v korenu spleta, v tej mapi izklopite izvajanje skript.
- Preverjanje samo na strežniku: Preverjanja z JavaScriptom v brskalniku izboljšajo uporabo, ne ščitijo pa.
Varen primer s finfo in naključnim imenom
Naslednji primer prikazuje jedro varne obdelave. Je namenoma kratek in ga je treba vgraditi v vašo aplikacijo, torej s prijavo, preverjanjem pooblastil, zaščito CSRF in beleženjem.
<?php
declare(strict_types=1);
const MAX_BYTES = 5 * 1024 * 1024; // 5 MB
const ERLAUBT = [
'application/pdf' => 'pdf',
'image/jpeg' => 'jpg',
'image/png' => 'png',
];
const ZIELORDNER = '/var/www/daten/uploads'; // zunaj korena spleta
$datei = $_FILES['dokument'] ?? null;
if (!is_array($datei) || $datei['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
exit('Upload fehlgeschlagen.');
}
if ($datei['size'] > MAX_BYTES || !is_uploaded_file($datei['tmp_name'])) {
http_response_code(400);
exit('Datei ungültig.');
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
$typ = $finfo->file($datei['tmp_name']);
if (!isset(ERLAUBT[$typ])) {
http_response_code(415);
exit('Dateityp nicht erlaubt.');
}
$name = bin2hex(random_bytes(16)) . '.' . ERLAUBT[$typ];
$ziel = ZIELORDNER . '/' . $name;
if (!move_uploaded_file($datei['tmp_name'], $ziel)) {
http_response_code(500);
exit('Speichern fehlgeschlagen.');
}
chmod($ziel, 0640);
// Izvirno ime shranite v podatkovno zbirko samo kot besedilo
// in ga ob vsakem izpisu escapirajte s htmlspecialchars().
Pri slikah se splača še en korak: sliko znova kodirajte z GD ali Imagick in pri tem zavrzite metapodatke. To ostalih preverjanj ne nadomesti, zmanjša pa preostalo tveganje zaradi vdelanih tujih podatkov.
Za dokumente iz neznanih virov, na primer prijave ali fotografije reklamacij, je pred posredovanjem smiseln še pregled na viruse. Ščiti manj spletni strežnik kot zaposlene, ki datoteke pozneje odprejo na svojih delovnih računalnikih. Poleg tega beležite vsako nalaganje s časom, računom, velikostjo datoteke in prepoznanim tipom, da je mogoče nenavadne vzorce pozneje slediti.
Pri CMS-jih in trgovinah vgrajene medijske knjižnice običajno prinesejo lastna preverjanja. Bolj tvegane so razširitve obrazcev, funkcije uvoza in samoprogramirane dodatne strani, ki datoteke shranjujejo mimo knjižnice. Prav ta mesta naj bodo pri pregledu prva na vrsti.
Datoteke iz zaščitene mape dostavljajte z Content-Disposition: attachment in X-Content-Type-Options: nosniff. Brskalnik potem problematičnih vsebin ne prikaže neposredno, ampak jih ponudi kot prenos.
Izklop izvajanja PHP v mapi za nalaganje
Tudi če datoteka z napačno vsebino zdrsne skozi, je spletni strežnik ne sme izvesti kot skripto. Ta druga zaščitna plast sodi na vsak strežnik, ki nalaganja shranjuje v korenu spleta.
Za Nginx s PHP-FPM:
location ^~ /uploads/ {
location ~* \.(php|phtml|phar)$ {
deny all;
}
}
Za Apache, najbolje neposredno v VirtualHost namesto v .htaccess, da pravila aplikacija ne more prepisati:
<Directory "/var/www/html/uploads">
AllowOverride None
<FilesMatch "\.(php|phtml|phar)$">
Require all denied
</FilesMatch>
</Directory>
Če PHP teče kot modul Apache (mod_php), lahko v istem bloku dodatno nastavite php_admin_flag engine off. Po spremembi s neškodljivo preizkusno datoteko, ki izpiše samo besedilo, preverite, da strežnik na zahtevo zanjo odgovori s 403.
Meje velikosti in povezava s PHP2Shell
Nalaganja so tesno povezana z nastavitvama PHP post_max_size in upload_max_filesize. V okviru PHP2Shell php.net kot vmesni ukrep priporoča nastavitev post_max_size na 8M, če nalaganja niso potrebna, ali na 32M z nalaganji, in upload_max_filesize pod to vrednostjo. To ni popolna zaščita in ne nadomesti posodobitve na odpravljeno različico PHP.
; php.ini ali pool FPM (php_admin_value), nato znova zaženite vse workerje
file_uploads = On
post_max_size = 32M
upload_max_filesize = 20M
max_file_uploads = 5
Če spletna stran nalaganj sploh ne potrebuje, je file_uploads = Off najčistejša rešitev. Katere nastavitve so smiselne do popravka, piše na strani Takojšnji ukrepi brez popravka. Ustrezne pravice za mape za nalaganje opisuje vodnik Pravice datotek na spletnem strežniku.
Tipične napake v funkcijah nalaganja
Pri pregledu obstoječih aplikacij se vedno znova pojavljajo isti vzorci. Obrazce ciljno preverite glede teh točk:
- Končnica se preverja samo delno, zato skozi zdrsnejo imena datotek z več končnicami.
- Izvirno ime iz obrazca pristane v poti shranjevanja. To odpira pot manipulaciji poti in prepisovanju obstoječih datotek.
- Nalaganja ležijo javno s predvidljivimi imeni. Pri prijavah ali pogodbah je to tudi težava z varstvom podatkov.
- Mapa za nalaganje je za spletni strežnik zapisljiva in hkrati izvršljiva.
- Stare razširitve za nalaganje ali vtičniki obrazcev se ne posodabljajo, čeprav je proizvajalec objavil varnostne posodobitve.
- Napake se ne beležijo. Zavrnjena nalaganja pa so zgodnji signal ciljnih poskusov.
Kako PHP SOS pomaga konkretno?
- Vaše funkcije nalaganja preverimo v kodi in v konfiguraciji strežnika ter konkretne šibkosti imenujemo s prioriteto.
- Blokado izvajanja v mapi za nalaganje, ustrezne pravice in meje velikosti uvedemo v okviru utrjevanja strežnika.
- Ob sumu v mapah za nalaganje iščemo vnesene skripte in jih očistimo prek naše odstranitve zlonamerne programske opreme.
- Na željo izvedbo neodvisno preverimo s penetracijskim testom.
Pogosta vprašanja
Ali zadošča, da ob nalaganju preverim končnico datoteke?
Ne. Končnica in tip MIME, ki ga sporoči brskalnik, izvirata od pošiljatelja in ju je mogoče poljubno izbrati. Vsebino preverite na strežniku, dodelite novo ime datoteke in blokirajte izvajanje skript v mapi za nalaganje.
Kje naj se shranjujejo naložene datoteke?
Najbolje zunaj javne spletne mape. Dostavo tedaj prevzame skripta, ki vnaprej preveri, ali sme uporabnik datoteko videti. Tako datotek ni mogoče neposredno priklicati ali izvesti.
Ali so datoteke SVG kot slike neškodljive?
Ne samodejno. SVG je XML in lahko vsebuje aktivne vsebine. SVG dovolite samo, če datoteke očistite ali jih dostavljate izključno kot prenos z ustrezno glavo Content-Disposition.
Ali ima velikost nalaganja kaj opraviti s PHP2Shell?
Da, posredno. php.net kot vmesni ukrep priporoča nižje vrednosti za post_max_size in upload_max_filesize. To tveganje zmanjša, vendar ne nadomesti posodobitve na odpravljeno različico PHP in ponovnega zagona vseh workerjev.