Aktuális helyzet: PHP2Shell. Két kritikus PHP-rés (CVSS 9,2) lehetővé teszi kártékony kód futtatását bejelentkezés nélkül. Javítások 2026. 10. 21. óta.Mi a teendő most →

Fájlfeltöltések biztonságos megvalósítása PHP-ban: PHP-feltöltés biztonsága

A feltöltési űrlapok a webshellek gyakori útja. Így ellenőrizze helyesen a fájltípusokat, tárolja biztonságosan a fájlokat, és akadályozza meg, hogy a szerver végrehajtsa a feltöltött szkripteket.

Állapot 5 perc olvasási időÚtmutatók

Röviden: A PHP-feltöltés biztonságánál nem egyetlen ellenőrzés dönt, hanem a kombináció: a fájltípus szerveroldali ellenőrzése, a fájlok átnevezése, tárolásuk a webgyökéren kívül, és a szkriptek végrehajtásának tiltása a feltöltési mappában. Egy ellenőrizetlen feltöltési űrlap az egyik klasszikus út, amelyen a támadók hátsó ajtót juttatnak egy webszerverre.

Miért kedvelt belépési pont a feltöltési űrlap

Minden fájlokat fogadó űrlap idegen adatokat ír a szerverére. Ide tartoznak a jelentkezési űrlapok, az ügyfélportálok, a képgalériák, a támogatási területek és a CMS-ek és webshopok sok bővítménye. Ha egy támadónak sikerül ott olyan fájlt elhelyeznie, amelyet a webszerver ezután PHP-ként hajt végre, tartós hátsó ajtója van.

A vezetőség számára ez azt jelenti: egy ártalmatlannak tűnő önéletrajz-feltöltés a legrosszabb esetben a teljes webszerver átvételéhez vezethet. Emellett a feltöltési mappákban gyakran személyes adatok vannak, amelyek hibás konfiguráció esetén nyilvánosan lekérhetők.

Az adminok és fejlesztők számára ez azt jelenti: az alkalmazáskódnak és a szerverkonfigurációnak egymáshoz kell illeniük. Az egyik szint gyengeségét gyakran a másik fogja fel, ha mindkettő szabályosan van megvalósítva. Hogyan találhatja meg a már bejuttatott fájlokat, azt a Webshellek felismerése és eltávolítása útmutató írja le.

A PHP-feltöltés biztonságának alapszabályai

A következő szabályok megfelelnek az OWASP Cheat Sheetek ajánlásainak, és az üzemben bevált:

  • Engedélylista tiltólista helyett: Csak kifejezetten engedélyezett fájltípusokat fogadjon el, például PDF-et, JPG-t és PNG-t. Az egyes kiterjesztések tiltólistái változatokkal és dupla kiterjesztésekkel megkerülhetők.
  • A tartalmat ellenőrizze, ne csak a kiterjesztést: A tényleges típust szerveroldalon állapítsa meg a finfo-val. A $_FILES-ban lévő MIME-típus a feladó adata, és nem megbízható.
  • Új fájlnév: Az eredeti nevet soha ne használja fájlnévként. Hozzon létre véletlenszerű nevet, és fűzze hozzá az engedélylistából származó kiterjesztést.
  • Tárolás a webgyökéren kívül: A fájlokat úgy mentse, hogy URL-en keresztül közvetlenül ne legyenek elérhetők. A kiszolgálás jogosultság-ellenőrzéssel ellátott szkripten keresztül történik.
  • A méret korlátozása: Az alkalmazásban, a PHP-ban és a webszerveren.
  • Nincs végrehajtás: Ha a feltöltéseknek mégis a webgyökérben kell lenniük, kapcsolja ki a szkriptek végrehajtását ebben a könyvtárban.
  • Ellenőrzés csak a szerveren: A böngészőben végzett JavaScript-ellenőrzések javítják a kezelhetőséget, de nem védenek.

Egy biztonságos példa finfo-val és véletlenszerű névvel

A következő példa a biztonságos feldolgozás magját mutatja. Szándékosan rövid, és be kell ágyazni az alkalmazásába, vagyis bejelentkezéssel, jogosultság-ellenőrzéssel, CSRF-védelemmel és naplózással együtt.

<?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'; // a webgyökéren kívül

$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);
// Az eredeti nevet csak szövegként tárolja az adatbázisban,
// és minden kiadásnál escape-elje a htmlspecialchars()-szal.

Képeknél érdemes egy további lépés: a képet GD-vel vagy Imagickkel újra kell kódolni, és közben a metaadatokat el kell dobni. Ez nem pótolja a többi ellenőrzést, de csökkenti a beágyazott idegen adatokból eredő maradék kockázatot.

Ismeretlen forrásból származó dokumentumoknál, például jelentkezéseknél vagy reklamációs fotóknál ezen felül célszerű egy vírusellenőrzés a továbbadás előtt. Ez kevésbé a webszervert védi, inkább a munkatársakat, akik a fájlokat később a munkaállomásukon megnyitják. Naplózzon emellett minden feltöltést idővel, fiókkal, fájlmérettel és felismert típussal, hogy a szokatlan minták később visszakövethetők legyenek.

A CMS-eknél és webshopoknál a beépített médiakönyvtárak többnyire saját ellenőrzéseket hoznak magukkal. Kockázatosabbak az űrlap-bővítmények, az importfunkciók és az önállóan programozott kiegészítő oldalak, amelyek a könyvtárat megkerülve mentik a fájlokat. Egy ellenőrzésnél éppen ezeket a helyeket nézze meg elsőként.

Tipp

A fájlokat a védett mappából Content-Disposition: attachment és X-Content-Type-Options: nosniff fejléccel szolgálja ki. Ekkor a böngésző a problémás tartalmakat nem jeleníti meg közvetlenül, hanem letöltésként kínálja fel.

A PHP-végrehajtás kikapcsolása a feltöltési mappában

Még ha egy hibás tartalmú fájl át is csúszik, a webszervernek nem szabad szkriptként végrehajtania. Ez a második védelmi réteg minden olyan szerveren kell, amely feltöltéseket a webgyökérben tárol.

Nginx PHP-FPM-mel:

location ^~ /uploads/ {
    location ~* \.(php|phtml|phar)$ {
        deny all;
    }
}

Apache esetén, a legjobb közvetlenül a VirtualHostban, nem egy .htaccess-ben, hogy a szabályt az alkalmazás ne tudja felülírni:

<Directory "/var/www/html/uploads">
    AllowOverride None
    <FilesMatch "\.(php|phtml|phar)$">
        Require all denied
    </FilesMatch>
</Directory>

Ha a PHP Apache-modulként (mod_php) fut, ugyanabban a blokkban emellett beállíthatja a php_admin_flag engine off értéket. A módosítás után egy ártalmatlan teszt fájllal, amely csak egy szöveget ad ki, ellenőrizze, hogy a szerver 403-mal válaszol a rá irányuló kérésre.

Méretkorlátok és a kapcsolat a PHP2Shellel

A feltöltések szorosan összefüggnek a post_max_size és az upload_max_filesize PHP-beállításokkal. A PHP2Shell kapcsán a php.net átmeneti intézkedésként azt ajánlja, hogy a post_max_size értékét állítsa 8M-ra, ha nincs szükség feltöltésekre, vagy 32M-ra feltöltésekkel, és az upload_max_filesize ennél kisebb maradjon. Ez nem teljes védelem, és nem pótolja a javított PHP-verzióra való frissítést.

; php.ini vagy FPM-pool (php_admin_value), utána indítsa újra az összes workert
file_uploads        = On
post_max_size       = 32M
upload_max_filesize = 20M
max_file_uploads    = 5

Ha egy weboldalnak egyáltalán nincs szüksége feltöltésekre, a file_uploads = Off a legtisztább megoldás. Hogy a javításig mely beállítások célszerűek, azt az Azonnali intézkedések javítás nélkül oldalon találja. A feltöltési könyvtárak megfelelő jogait a Fájljogosultságok a webszerveren írja le.

Tipikus hibák a feltöltési funkciókban

A meglévő alkalmazások átnézésekor újra és újra ugyanazok a minták bukkannak fel. Ellenőrizze az űrlapjait célzottan ezekre a pontokra:

  • A kiterjesztést csak részben ellenőrzik, így a több kiterjesztéssel rendelkező fájlnevek átcsúsznak.
  • Az űrlapból származó eredeti név a tárolási útvonalba kerül. Ez utat nyit az útvonal-manipulációnak és a meglévő fájlok felülírásának.
  • A feltöltések nyilvánosan, kiszámítható nevekkel vannak. Jelentkezéseknél vagy szerződéseknél ez adatvédelmi probléma is.
  • A feltöltési mappa a webszerver számára írható és egyben futtatható.
  • A régi feltöltési bővítményeket vagy űrlap-plugineket nem frissítik, noha a gyártó biztonsági frissítéseket adott ki.
  • A hibákat nem naplózzák. Az elutasított feltöltések azonban korai jelzések a célzott kísérletekről.

Hogyan segít konkrétan a PHP SOS?

  • Ellenőrizzük a feltöltési funkcióit a kódban és a szerverkonfigurációban, és prioritással megnevezzük a konkrét gyengeségeket.
  • A szerver-keményítés keretében beállítjuk a végrehajtási tiltást a feltöltési mappában, a megfelelő jogokat és a méretkorlátokat.
  • Gyanú esetén átvizsgáljuk a feltöltési könyvtárakat bejuttatott szkriptek után, és megtisztítjuk őket a kártevő-eltávolítással.
  • Kívánságra a megvalósítást egy penetrációs teszttel függetlenül ellenőriztetjük.

Gyakori kérdések

Elég a fájl kiterjesztését ellenőrizni feltöltéskor?

Nem. A kiterjesztés és a böngésző által jelentett MIME-típus a feladótól származik, és szabadon megválasztható. Ellenőrizze a tartalmat szerveroldalon, adjon új fájlnevet, és tiltsa le a szkriptek végrehajtását a feltöltési könyvtárban.

Hol érdemes tárolni a feltöltött fájlokat?

A legjobb a nyilvános webkönyvtáron kívül. A kiszolgálást ekkor egy szkript végzi, amely előtte ellenőrzi, hogy a felhasználó láthatja-e a fájlt. Így a fájlok sem közvetlenül nem hívhatók meg, sem nem futtathatók.

Ártalmatlanok az SVG-fájlok képként?

Nem automatikusan. Az SVG XML, és aktív tartalmat tartalmazhat. Csak akkor engedélyezze az SVG-t, ha megtisztítja a fájlokat, vagy kizárólag letöltésként, megfelelő Content-Disposition fejléccel szolgálja ki őket.

Van köze a feltöltési méretnek a PHP2Shellhez?

Igen, közvetve. A php.net átmeneti intézkedésként alacsonyabb értékeket ajánl a post_max_size és az upload_max_filesize számára. Ez csökkenti a kockázatot, de nem pótolja a javított PHP-verzióra való frissítést és az összes worker újraindítását.

Források

Azonnali kapcsolat

Minden óra számít. Írjon nekünk most.

Ismertesse röviden a rendszert, a PHP-verziót és a megfigyelését. Jelentkezünk, tisztázzuk a helyzetet, és távolról dolgozunk, amíg az incidens le nem zárul és dokumentálva nem lesz.

Azonnali segítség