# PHP vykdymo įkėlimų aplankuose draudimas

> PHP vykdymo draudimas įkėlimuose: raskite įrašomus aplankus, teisingai nustatykite užraktus Nginx, Apache ir PHP-FPM ir išbandykite su nekenksmingu failu.

Šaltinis: https://phpsos.de/lt/blog/php-in-uploads-verbieten/  
Būsena: 2026-10-25  
Teikėjas: PHP SOS, PHP avarinė pagalba ir serverio sauga. Skubi pagalba per „WhatsApp“: https://wa.me/491736494914?text=Sveiki%2C%20PHP%20SOS%2C%20mums%20reikia%20pagalbos%20su%20m%C5%ABs%C5%B3%20PHP%20serveriu.%20%C4%AEmon%C4%97%3A%20%E2%80%A6%20Svetain%C4%97%3A%20%E2%80%A6

**Trumpai:** norėdami uždrausti PHP vykdymą įkėlimuose, pirmiausia nustatykite visus aplankus, į kuriuos PHP gali rašyti, ir kiekviename jų užblokuokite scenarijų vykdymą serverio konfigūracijoje, o ne per `.htaccess`. Nginx užraktas turi suveikti prieš bendrą PHP bloką, Apache jis priklauso VirtualHost su `AllowOverride None`. `security.limit_extensions = .php` FPM baseine ir bandymas su nekenksmingu failu užbaigia darbą.

## Kodėl būtent dabar svarbūs įkėlimų aplankai

Po kritinės spragos, tokios kaip PHP2Shell, užpuolikai retai nori vykdyti kodą tik kartą. Jie nori sugrįžti, net kai serveris vėliau bus pataisytas. Paprasčiausias kelias tam yra webshell: maža PHP failas, padėtas įrašomame aplanke ir vėliau iškviečiamas per naršyklę.

Pataisa tokio failo nepašalina. Kas nuo 2026 m. spalio 20 d. buvo prisijungęs prie interneto nepataisytas, turėtų ne tik atnaujinti, bet ir patikrinti, ar kur nors nėra naujų PHP failų, ir ateityje užkirsti kelią jų vykdymui. Kaip aiškinti radinius, aprašo [PHP failai įkėlimų aplanke: radinių teisingas aiškinimas](https://phpsos.de/lt/blog/php-dateien-im-upload-ordner/).

Vykdymo užraktas veikia antrąją sąlygą. Jis neužkerta kelio failo padėjimui, bet neleidžia serveriui jo traktuoti kaip programos.

## Pirmiausia inventorizacija: kur PHP gali rašyti?

Dauguma instrukcijų mini tik įkėlimų aplanką. Praktikoje PHP programa rašo daug daugiau vietų. Kiekvienai, pasiekiamai per žiniatinklio serverį, reikia užrakto.

| Aplanko tipas | Tipinis turinys | Kodėl įrašomas |
|---|---|---|
| Įkėlimai, medija | paveikslėliai, PDF, priedai | naudotojai ir redakcija įkelia failus |
| Talpykla | sugeneruoti puslapiai, miniatiūros | programa pagreitina pateikimą |
| Temp, importas, eksportas | CSV failai, tarpinės būsenos | sąsajos ir duomenų mainai |
| Atsarginės kopijos žiniatinklio šakniniame kataloge | `.zip`, `.sql` | plėtiniai saugo „vietoje“ |
| Žurnalai žiniatinklio šakniniame kataloge | klaidų ir derinimo žurnalai | neteisingai sukonfigūruotos programos |

Kokie tai aplankai jūsų serveryje, parodo paieška vykdymo naudotojo teisėmis. Ji nieko nekeičia:

```bash
# Visi aplankai po /var/www, į kuriuos PHP naudotojas gali rašyti
# (pritaikyti naudotoją: www-data, nginx, apache arba savas baseino naudotojas)
sudo -u www-data find /var/www -type d -writable 2>/dev/null | sort
# Ar šiuose aplankuose jau yra PHP failų?
sudo -u www-data find /var/www -type d -writable -print0 2>/dev/null \
  | xargs -0 -I{} find {} -maxdepth 1 -type f -iname "*.ph*" 2>/dev/null
```

Jei pirmoji paieška grąžina visą žiniatinklio šakninį katalogą, programos kodas priklauso vykdymo naudotojui. Tai prieš tai reikėtų pakeisti, kaip aprašo gidas [Failų teisės žiniatinklio serveryje](https://phpsos.de/lt/ratgeber/dateirechte-webserver/). Kitaip nėra aplanko, kurio nereikėtų užrakinti.

## PHP vykdymo įkėlimuose draudimas: Nginx

Nginx atveju lemia eilės tvarka. Pasak Nginx dokumentacijos, reguliarieji reiškiniai tikrinami konfigūracijos failo eilės tvarka, ir laimi pirmas atitikmuo. Jei bendras blokas `location ~ \.php$` yra prieš jūsų užraktą, failas vykdomas. Paprasta prefiksinė location be `^~` dėl tos pačios priežasties neapsaugo.

Saugu yra vienas reguliarusis reiškinys visiems užrakintiems aplankams, esantis prieš PHP bloką. Jis apima ir retai naudojamus plėtinius:

```nginx
server {
    # ... pagrindinė konfigūracija ...

    # 1. Įrašomų aplankų užraktas, PRIVALO būti prieš PHP bloką
    location ~* ^/(uploads|media|cache|tmp|export)/.*\.(php\d?|phtml|phar|pht|phps)$ {
        deny all;
    }

    # 2. Bendras PHP blokas: perduoti tik egzistuojančius failus
    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/seite1.sock;
    }
}
```

Aplankų pavadinimus pritaikykite pagal savo inventorizaciją. Programoms su vienu įėjimo tašku kelias per leidžiamųjų sąrašą dar stipresnis; šabloną rodo [Saugi Nginx konfigūracija PHP](https://phpsos.de/lt/blog/nginx-fuer-php-absichern/).

## Apache ir PHP-FPM: užraktas tinkamoje vietoje

Apache užraktas priklauso serverio konfigūracijai arba VirtualHost. `.htaccess` įkėlimų aplanke netinka, nes jį gali pakeisti kiekvienas, kuris ten gali rašyti. Todėl visam žiniatinklio šakniniam katalogui galioja `AllowOverride None`. Pasak Apache dokumentacijos, `AllowOverride` leidžiamas tik `<Directory>` blokuose be reguliariųjų reiškinių, taigi nustatykite jį šakniniame kataloge, o užraktą per `<DirectoryMatch>` žemiau:

```apache
<Directory /var/www/seite1/public>
    AllowOverride None
    Require all granted
</Directory>

<DirectoryMatch "^/var/www/seite1/public/(uploads|media|cache|tmp|export)/">
    <FilesMatch "\.(php\d?|phtml|phar|pht|phps)$">
        Require all denied
    </FilesMatch>
</DirectoryMatch>
```

Jei dar veikia mod_php, tame pačiame bloke pridėkite `php_admin_flag engine off`. Su PHP-FPM antras barjeras veikia baseine: `security.limit_extensions` nustato, kuriuos plėtinius FPM apskritai vykdo. Pasak PHP vadovo, numatytieji yra `.php .phar`; rekomenduojamas apribojimas iki `.php`.

```ini
; baseine, pvz., /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
```

## Bandymas su nekenksmingu failu

Ar užraktas veikia, parodo tik bandymas. Į kiekvieną užrakintą aplanką trumpam padėkite failą, kuris tik išveda tekstą, iškvieskite jį per domeną ir po to ištrinkite.

1. Patikrinti konfigūraciją: `nginx -t` arba `apachectl configtest`, tada įkelti iš naujo.
2. Sukurti bandomąjį failą, pavyzdžiui, `uploads/sperrtest.php` su turiniu `<?php echo 'ausgefuehrt';`.
3. Iškviesti su `curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/uploads/sperrtest.php`. Tikimasi `403`.
4. Jei vietoj to pasirodo `200` ir tekstas „ausgefuehrt“, užraktas neveikia. Patikrinti konfigūraciją ir eilės tvarką.
5. Bandomąjį failą ištrinti ir bandymą pakartoti kiekvienam aplankui ir kiekvienai svetainei.

> **Svarbu:**
> Jei per inventorizaciją įrašomuose aplankuose randate nežinomų PHP failų, nieko neskubėkite trinti. Pirmiausia išsaugokite būseną ir žurnalus, nes šie failai yra įrodymai. Kaip elgtis toliau, aprašo [Webshell atpažinimas ir šalinimas](https://phpsos.de/lt/ratgeber/webshell-erkennen/).

Kaip įkėlimo funkcijos kode kuriamos saugiai, su tipo patikra ir laikymu už žiniatinklio šakninio katalogo ribų, aprašyta gide [Saugus failų įkėlimas PHP](https://phpsos.de/lt/ratgeber/datei-upload-sicher/).

## Išvada: rašyti taip, vykdyti ne

Vykdymo užraktas įrašomuose aplankuose yra viena veiksmingiausių pavienių priemonių prieš nuolatines užpakalines duris. Jis kainuoja kelias konfigūracijos eilutes ir tvarkingai sukurtose programose nieko nesulaužo. Lemia trys dalykai: pilna inventorizacija, o ne tik akivaizdus įkėlimų aplankas, teisinga eilės tvarka Nginx arba teisingas lygmuo Apache ir tikras bandymas su nekenksmingu failu.

Papildžius atskirais programos kodo savininkais, `security.limit_extensions` baseine ir reguliaria naujų PHP failų paieška, atsiranda būklė, kai padėtas failas yra erzinantis, bet vargu ar bepanaudojamas. Tai nepakeičia nei atnaujinimo, nei pėdsakų paieškos, bet atima iš užpuolikų vieną svarbiausių įrankių.

## Kaip PHP SOS padeda konkrečiai?

- **Inventorizacija:** nustatome visus įrašomus aplankus kiekvienai svetainei ir tikriname, ar juose nėra PHP failų.
- **Nustatyti užraktus:** vykdymo užraktus įrašome Nginx, Apache ir PHP-FPM, teisinga eilės tvarka ir be `.htaccess` priklausomybės.
- **Išbandyti:** kiekvieną užraktą tikriname nekenksmingu failu ir dokumentuojame rezultatą.
- **Išvalyti:** radinių atveju atliekame pėdsakų išsaugojimą ir [kenkėjiškų programų šalinimą](https://phpsos.de/lt/leistungen/malware-entfernung/).


## Dažni klausimai

**Ar PHP uždrausti pakanka .htaccess įkėlimų aplanke?**  
Nepatikimai. Kas gali rašyti į aplanką, gali ir pakeisti ar pakeisti .htaccess. Užraktas priklauso serverio konfigūracijai arba VirtualHost, o žiniatinklio šakniniam katalogui turėtų galioti AllowOverride None.

**Kuriuos aplankus turiu užrakinti?**  
Visus aplankus, į kuriuos PHP naudotojas gali rašyti ir kurie pasiekiami per žiniatinklio serverį. Be įkėlimų aplankų tai dažnai talpyklos, laikinieji, importo, eksporto ir atsarginių kopijų katalogai. Nustatykite juos paieška vykdymo naudotojo teisėmis.

**Ar užraktas sugadins mano svetainę?**  
Paprastai ne, nes tvarkingose programose įkėlimų ir talpyklos aplankuose nėra scenarijų, kurie iškviečiami tiesiogiai. Tačiau kai kurie plėtiniai ten vis dėlto deda PHP failus. Todėl po perėjimo išbandykite svarbiausias funkcijas.

**Ar užraktas apsaugo nuo PHP2Shell?**  
Ne. PHP2Shell yra PHP interpretatoriaus spraga, kuri uždaroma tik atnaujinimu ir visų darbinių procesų (worker) paleidimu iš naujo. Tačiau užraktas neleidžia padėto failo vėliau iškviesti per naršyklę ir naudoti kaip nuolatinių užpakalinių durų.

## Šaltiniai

- [Nginx: location blokų pasirinkimas](https://nginx.org/en/docs/http/ngx_http_core_module.html)
- [Apache: pagrindinės funkcijos (AllowOverride, FilesMatch)](https://httpd.apache.org/docs/2.4/mod/core.html)
- [PHP vadovas: FPM konfigūracija (security.limit_extensions)](https://www.php.net/manual/en/install.fpm.configuration.php)
- [OWASP Cheat Sheets (File Upload)](https://cheatsheetseries.owasp.org/)
