Īsi: PHP augšupielāžu drošībā izšķir nevis atsevišķa pārbaude, bet kombinācija: faila tipu pārbaudīt serverī, failus pārdēvēt, glabāt ārpus webroot un augšupielāžu mapē neatļaut skriptu izpildi. Nepārbaudīta augšupielādes veidlapa ir viens no klasiskajiem ceļiem, pa kuru uzbrucēji ievieš slēpto piekļuvi tīmekļa serverī.
Kāpēc augšupielādes veidlapas ir iecienīta ieejas vieta
Katra veidlapa, kas pieņem failus, raksta svešus datus jūsu serverī. Tur pieder pieteikumu veidlapas, klientu portāli, attēlu galerijas, atbalsta sadaļas un daudzi CMS un veikalu paplašinājumi. Ja uzbrucējam izdodas tur novietot failu, ko tīmekļa serveris pēc tam izpilda kā PHP, viņam ir pastāvīga slēptā piekļuve.
Vadībai tas nozīmē: šķietami nekaitīga CV augšupielāde sliktākajā gadījumā var novest pie visa tīmekļa servera pārņemšanas. Turklāt augšupielāžu mapēs bieži atrodas personas dati, kas nepareizas konfigurācijas gadījumā ir publiski pieejami.
Administratoriem un izstrādātājiem tas nozīmē: lietojumprogrammas kodam un servera konfigurācijai jāsader. Vājumu vienā līmenī bieži kompensē otrs, ja abi ir tīri īstenoti. Kā atrast jau ievadītus failus, apraksta ceļvedis Webshell atklāšana un noņemšana.
PHP augšupielāžu drošības pamatnoteikumi
Turpmākie noteikumi atbilst OWASP Cheat Sheet ieteikumiem un darbībā ir sevi pierādījuši:
- Atļauju saraksts, nevis aizliegumu saraksts: Pieņemt tikai skaidri atļautus failu tipus, piemēram, PDF, JPG un PNG. Aizliegumu sarakstus atsevišķiem paplašinājumiem var apiet ar variantiem un dubultiem paplašinājumiem.
- Pārbaudīt saturu, nevis tikai paplašinājumu: Faktisko tipu serverī noteikt ar
finfo. MIME tips$_FILESir sūtītāja norāde un nav uzticams. - Jauns faila nosaukums: Oriģinālo nosaukumu nekad neizmantot kā faila nosaukumu. Ģenerēt nejaušu nosaukumu un pievienot paplašinājumu no atļauju saraksta.
- Glabāšana ārpus webroot: Failus saglabāt tā, lai tie nebūtu tieši sasniedzami caur URL. Piegāde caur skriptu ar tiesību pārbaudi.
- Ierobežot lielumu: Lietojumprogrammā, PHP un tīmekļa serverī.
- Nekādas izpildes: Ja augšupielādēm tomēr jāatrodas webroot, šajā direktorijā skriptu izpildi izslēgt.
- Pārbaude tikai serverī: JavaScript pārbaudes pārlūkā uzlabo lietošanu, bet neaizsargā.
Drošs piemērs ar finfo un nejaušu nosaukumu
Turpmākais piemērs rāda drošas apstrādes kodolu. Tas ir apzināti īss, un tas jāiestrādā jūsu lietojumprogrammā, tātad ar pieteikšanos, tiesību pārbaudi, CSRF aizsardzību un protokolēšanu.
<?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'; // ārpus webroot
$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);
// Oriģinālo nosaukumu saglabāt datubāzē tikai kā tekstu
// un katrā izvadē eskēpēt ar htmlspecialchars().
Attēliem ir vērts veikt vēl vienu soli: attēlu pārkodēt ar GD vai Imagick un pie tam atmest metadatus. Tas neaizstāj citas pārbaudes, bet samazina atlikušo risku no iegultiem svešiem datiem.
Dokumentiem no nezināmiem avotiem, piemēram, pieteikumiem vai reklamāciju fotogrāfijām, papildus lietderīga ir vīrusu skenēšana pirms tālākas nodošanas. Tā mazāk aizsargā tīmekļa serveri, vairāk darbiniekus, kas failus vēlāk atver savos darba datoros. Protokolējiet arī katru augšupielādi ar laiku, kontu, faila lielumu un atpazīto tipu, lai neparastus modeļus vēlāk varētu izsekot.
CMS un veikalos iebūvētās multivides bibliotēkas parasti nes līdzi savas pārbaudes. Riskantāki ir veidlapu paplašinājumi, importa funkcijas un pašu programmētas papildu lapas, kas failus saglabā garām bibliotēkai. Tieši šīs vietas pārbaudē jāaplūko vispirms.
Failus no aizsargātās mapes piegādājiet ar Content-Disposition: attachment un X-Content-Type-Options: nosniff. Tad pārlūks problemātisku saturu nerāda tieši, bet piedāvā to kā lejupielādi.
PHP izpildes izslēgšana augšupielāžu mapē
Pat ja fails ar nepareizu saturu izslīd cauri, tīmekļa serveris to nedrīkst izpildīt kā skriptu. Šim otrajam aizsardzības slānim jābūt katrā serverī, kas augšupielādes glabā webroot.
Nginx ar PHP-FPM:
location ^~ /uploads/ {
location ~* \.(php|phtml|phar)$ {
deny all;
}
}
Apache, vislabāk tieši VirtualHost, nevis .htaccess, lai noteikumu lietojumprogramma nevarētu pārrakstīt:
<Directory "/var/www/html/uploads">
AllowOverride None
<FilesMatch "\.(php|phtml|phar)$">
Require all denied
</FilesMatch>
</Directory>
Ja PHP darbojas kā Apache modulis (mod_php), tajā pašā blokā varat papildus iestatīt php_admin_flag engine off. Pēc izmaiņas ar nekaitīgu testa failu, kas izvada tikai tekstu, pārbaudiet, vai serveris uz pieprasījumu atbild ar 403.
Lieluma ierobežojumi un saistība ar PHP2Shell
Augšupielādes cieši saistītas ar PHP iestatījumiem post_max_size un upload_max_filesize. PHP2Shell sakarā php.net kā pagaidu pasākumu iesaka post_max_size iestatīt uz 8M, ja augšupielādes nav vajadzīgas, vai uz 32M ar augšupielādēm, un upload_max_filesize turēt zemāk. Tā nav pilnīga aizsardzība, un tā neaizstāj atjauninājumu uz izlabotu PHP versiju.
; php.ini vai FPM pūls (php_admin_value), pēc tam pārstartēt visus darbprocesus
file_uploads = On
post_max_size = 32M
upload_max_filesize = 20M
max_file_uploads = 5
Ja vietnei augšupielādes nav vajadzīgas vispār, file_uploads = Off ir tīrākais risinājums. Kuri iestatījumi līdz ielāpam ir lietderīgi, rakstīts lapā Tūlītējie pasākumi bez ielāpa. Piemērotas tiesības augšupielāžu direktorijiem apraksta Failu tiesības tīmekļa serverī.
Tipiskas kļūdas augšupielādes funkcijās
Pārskatot esošās lietojumprogrammas, atkal un atkal parādās tie paši modeļi. Pārbaudiet savas veidlapas mērķtiecīgi uz šiem punktiem:
- Paplašinājums tiek pārbaudīts tikai daļēji, tāpēc cauri izslīd faila nosaukumi ar vairākiem paplašinājumiem.
- Oriģinālais nosaukums no veidlapas nonāk glabāšanas ceļā. Tas atver ceļus ceļa manipulācijai un esošu failu pārrakstīšanai.
- Augšupielādes atrodas publiski ar paredzamiem nosaukumiem. Pieteikumu vai līgumu gadījumā tā ir arī datu aizsardzības problēma.
- Augšupielāžu mape tīmekļa serverim ir rakstāma un vienlaikus izpildāma.
- Vecie augšupielāžu paplašinājumi vai veidlapu spraudņi netiek atjaunināti, kaut gan ražotājs ir publicējis drošības atjauninājumus.
- Kļūdas netiek protokolētas. Noraidītas augšupielādes tomēr ir agrīns signāls par mērķtiecīgiem mēģinājumiem.
Kā PHP SOS palīdz konkrēti?
- Pārbaudām jūsu augšupielādes funkcijas kodā un servera konfigurācijā un nosaucam konkrētas ievainojamības ar prioritāti.
- Ieviešam izpildes bloķēšanu augšupielāžu mapē, piemērotas tiesības un lieluma ierobežojumus servera nostiprināšanas ietvaros.
- Aizdomu gadījumā pārmeklējam augšupielāžu direktorijus uz ievadītiem skriptiem un attīrām tos ar mūsu ļaunprogrammatūras noņemšanu.
- Pēc vēlēšanās īstenojumu neatkarīgi pārbaudām ar penetrācijas testu.
Biežāk uzdotie jautājumi
Vai pietiek ar faila paplašinājuma pārbaudi augšupielādes laikā?
Nē. Paplašinājums un pārlūka paziņotais MIME tips nāk no sūtītāja un ir brīvi izvēlami. Pārbaudiet saturu serverī, piešķiriet jaunu faila nosaukumu un bloķējiet skriptu izpildi augšupielāžu direktorijā.
Kur glabāt augšupielādētos failus?
Vislabāk ārpus publiskā tīmekļa direktorija. Piegādi tad veic skripts, kas iepriekš pārbauda, vai lietotājs drīkst failu redzēt. Tā faili nav ne tieši izsaucami, ne izpildāmi.
Vai SVG faili kā attēli ir nekaitīgi?
Ne automātiski. SVG ir XML, un tas var saturēt aktīvu saturu. Atļaujiet SVG tikai tad, ja failus tīrāt vai piegādājat tikai kā lejupielādi ar piemērotu Content-Disposition galveni.
Vai augšupielādes lielumam ir sakars ar PHP2Shell?
Jā, netieši. php.net kā pagaidu pasākumu iesaka zemākas post_max_size un upload_max_filesize vērtības. Tas samazina risku, bet neaizstāj atjauninājumu uz izlabotu PHP versiju un visu darbprocesu pārstartēšanu.