Dabartinė padėtis: PHP2Shell. Du kritiniai PHP pažeidžiamumai (CVSS 9,2) leidžia vykdyti kenkėjišką kodą be prisijungimo. Pataisos nuo 2026-10-21.Ką dabar daryti →

Saugi Nginx konfigūracija PHP

Dauguma pažeidžiamumų Nginx sąrankose PHP slypi ne Nginx, o kelių PHP location eilučių. Sužinokite, kaip sukonfigūruoti perdavimą PHP-FPM taip, kad būtų vykdomi tik norimi scenarijai.

Būsena 5 min. skaitymoSutvirtinimas ir konfigūracija

Trumpai: norėdami saugiai sukonfigūruoti Nginx PHP, į PHP-FPM perduokite tik scenarijus, kurie tikrai egzistuoja, Front-Controller programoms net tik index.php. Prie to priklauso užblokuoti dotfiles, tokie kaip .git ir .env, numatytasis serveris nežinomiems pagrindinio kompiuterio vardams (hostname), tinkamos dydžio ribos ir security.limit_extensions = .php baseine. Tai neapsaugo nuo spragų pačiame PHP, bet riboja, kas po klaidos gali būti vykdoma.

Pavojingiausios eilutės yra PHP location

Po PHP2Shell daugelis komandų tikrina savo PHP-FPM versijas ir baseinus, kaip aprašo puslapis Nginx su PHP-FPM apsauga, ir po atnaujinimo iš naujo paleidžia visus darbinius procesus (worker). Antras žvilgsnis skiriamas pačiai Nginx konfigūracijai. Būtent ten nusprendžiama, kurie failai apskritai vykdomi kaip PHP.

Daugelyje konfigūracijų yra blokas, kuris kiekvieną užklausą .php perduoda PHP-FPM, nesvarbu, kur failas yra. Jei įterptas PHP failas patenka į įkėlimų aplanką, serveris jį vykdo. Iš failo klaidos taip atsiranda užpakalinės durys.

Šis straipsnis koncentruojasi į Nginx pusę: kurios direktyvos svarbios, kaip veikia location blokų eilės tvarka ir kaip patikrinti rezultatą.

Kaip Nginx nusprendžia, kuris blokas taikomas

Kas nori saugiai sukonfigūruoti Nginx PHP, turi žinoti location blokų pasirinkimą. Pasak Nginx dokumentacijos, jis vyksta taip:

  1. Tikslus atitikmuo su location = iš karto baigia paiešką.
  2. Tarp prefiksinių location įsimenama ilgiausia tinkama. Jei ji turi ^~, reguliarieji reiškiniai nebetikrinami.
  3. Kitu atveju reguliarieji reiškiniai (~, ~*) tikrinami konfigūracijos failo eilės tvarka; laimi pirmas atitikmuo.
  4. Jei joks reguliarusis reiškinys netinka, taikoma įsimintoji prefiksinė location.

Iš to išplaukia dvi praktinės taisyklės. PHP blokavimas įkėlimų aplankuose turi būti sukurtas arba kaip ^~ prefiksas, arba kaip reguliarusis reiškinys prieš bendrą PHP bloką. O įprasta prefiksinė location, pavyzdžiui, location /uploads/, neapsaugo, nes .php reguliarusis reiškinys ją nustelbia.

Saugi bazinė konfigūracija

Toliau pateiktas pavyzdys rodo serverio bloką programai su Front-Controller, kaip įprasta Laravel, Symfony, Shopware 6 ar daugelyje savo kūrimo programų. Kelius, lizdą ir sertifikatus pritaikykite.

server {
    listen 443 ssl;
    server_name www.example.de;
    root /var/www/seite1/public;
    index index.php;

    ssl_certificate     /etc/ssl/seite1/fullchain.pem;
    ssl_certificate_key /etc/ssl/seite1/privkey.pem;

    server_tokens off;
    client_max_body_size 32m;

    # Leisti Let's Encrypt ir kitus žinomus kelius
    location ^~ /.well-known/ {
        try_files $uri =404;
    }

    # Užblokuoti paslėptus failus ir aplankus (.git, .env, .htaccess)
    location ~ /\. {
        deny all;
    }

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Tik Front-Controller perduodamas PHP-FPM
    location = /index.php {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_hide_header X-Powered-By;
        fastcgi_pass unix:/run/php/seite1.sock;
    }

    # Joks kitas PHP failas nevykdomas
    location ~ \.php$ {
        return 404;
    }
}

$realpath_root išsprendžia simbolines nuorodas. Tai svarbu diegiant su besikeičiančia simboline nuoroda į dabartinį leidimą (release), kad PHP-FPM ir OPcache matytų teisingą kelią. Taip pat atkreipkite dėmesį: pasak Nginx dokumentacijos, fastcgi_param direktyvos iš aukštesnių lygių paveldimos tik tada, kai dabartiniame lygyje savų nėra. Todėl include fastcgi_params; priklauso tam pačiam blokui.

Klasikiniai CMS, tokie kaip WordPress, TYPO3 ar Contao, turi kelis įėjimo taškus. Ten Front-Controller bloką pakeiskite bendra PHP location, kuri perduoda tik egzistuojančius failus (try_files $uri =404;), ir užblokuokite vykdymą visuose įrašomuose aplankuose. Kaip tai pasiekti, aprašyta skyriuje PHP vykdymo įkėlimų aplankuose draudimas.

Antra apsauga PHP-FPM

Nginx nusprendžia, kas perduodama, PHP-FPM nusprendžia, ką vykdo. Pasak PHP vadovo, PHP-FPM numatytai vykdo failus su .php ir .phar ir pats rekomenduoja tai apriboti iki .php. Tai pagauna žiniatinklio serverio konfigūracijos klaidas.

; baseine, pvz., /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Lizdas turėtų būti pasiekiamas tik Nginx. FPM prievadai tinkle, pavyzdžiui, 9000, neturi būti atveriami į išorę. Kaip serveris apskritai rodo tik reikalingus prievadus, aprašo Ugniasienė žiniatinklio serveriui: atverti tik reikalingus prievadus.

Nežinomi hostname ir kiti reguliavimo varžtai

Be savo numatytojo serverio Nginx užklausas nežinomiems hostname atsako pirmuoju tinkamu serverio bloku. Automatizuoti skenavimai, kurie kreipiasi tik į IP adresą, tada patenka tiesiai į jūsų programą. Atskiras numatytasis serveris tokias užklausas nutraukia be atsakymo.

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
    return 444;
}

Kiti pasiteisinę punktai:

Reguliavimo varžtas Rekomendacija Paskirtis
server_tokens off jokio versijos numerio antraštėje ir klaidų puslapiuose
client_max_body_size pagal post_max_size dideles užklausas atmesti anksti
autoindex išjungtas (numatytasis) jokių katalogų sąrašų
fastcgi_hide_header X-Powered-By PHP versijos neišduoti į išorę
Būsenos puslapiai pm.status_path tik viduje jokių eksploatacijos duomenų viešai
Atsarginių kopijų failai .sql, .zip, .bak žiniatinklio šakniniame kataloge užblokuoti arba pašalinti jokio duomenų bazių atsisiuntimo

Daugiau apie versijų duomenis rasite straipsnyje expose_php ir Server antraštė.

Kitas reguliavimo varžtas liečia leidžiamus HTTP metodus. Daugumai svetainių reikia tik GET, HEAD ir POST. Su limit_except kitus metodus galima atmesti location bloke; pasak Nginx dokumentacijos, GET leidimas automatiškai leidžia ir HEAD. Iš anksto patikrinkite, ar jūsų programos sąsajos nenaudoja, pavyzdžiui, PUT ar DELETE, nes REST API tai daro dažnai.

Išbandykite prieš iš naujo įkeldami

Kiekvieną pakeitimą pirmiausia patikrinkite su nginx -t ir tik tada iš naujo įkelkite Nginx. Po to elgseną iš išorės išbandykite įprastomis užklausomis į savo domeną:

sudo nginx -t && sudo systemctl reload nginx
# Tikimasi: 403 arba 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env
# Tikimasi: 404, nes vykdomas tik Front-Controller
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Kurie blokai perduoda PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"

Prieš kiekvieną didesnį pakeitimą išsaugokite pilną nginx -T išvestį su data. Joje yra visa veiksminga konfigūracija, įskaitant visus įtrauktus failus. Jei po pakeitimo kas nors nepavyksta, palyginimas iš karto parodo, kas skiriasi. Kitos kritinės spragos atveju taip turėsite ir patikimą inventorizacijos pagrindą nereikalaujant pirma rinkti failų.

Patarimas

Konfigūraciją pirmiausia keiskite testinėje aplinkoje arba serverio bloko kopijoje. Pamirštas įėjimo taškas, pavyzdžiui, mokėjimo atgalinis kvietimas (callback), kitaip pastebimas tik tada, kai nebelieka užsakymų.

Kaip PHP SOS padeda konkrečiai?

  • Perskaityti konfigūraciją: visą Nginx konfigūraciją analizuojame su nginx -T ir kiekvieną PHP perdavimą priskiriame jo svetainei ir baseinui.
  • Nustatyti įėjimo taškus: kartu su jūsų kūrėjais nustatome, kurie scenarijai turi būti vykdomi, ir užblokuojame likusius.
  • Įgyvendinti ir išbandyti: pritaikome serverio blokus ir baseinus, tikriname su nginx -t ir išbandome formas, mokėjimo kelius ir įkėlimus.
  • Apsaugoti ilgam: konfigūracija tampa mūsų serverio sutvirtinimo ir jūsų serverio dokumentacijos dalimi.

Dažni klausimai

Ar po PHP atnaujinimo reikia iš naujo paleisti Nginx?

PHP pataisai ne, nes Nginx neturi PHP. Iš naujo paleisti reikia visas PHP-FPM paslaugas. Jei kartu keičiate ir Nginx konfigūraciją, prieš tai patikrinkite ją su nginx -t ir tada iš naujo įkelkite Nginx.

Kodėl PHP perduoti tik index.php?

Daugelis šiuolaikinių programų turi vieną įėjimo tašką, Front-Controller. Jei PHP-FPM perduodamas tik šis failas, įterpto PHP failo kitoje vietoje per naršyklę vykdyti nebus įmanoma. Sistemose su daug įėjimo taškų šis šablonas neįmanomas.

Ką duoda security.limit_extensions PHP-FPM?

Nustatymas nurodo, kuriuos failų plėtinius PHP-FPM vykdo kaip scenarijų. Pasak PHP vadovo, numatytieji yra .php .phar; rekomenduojama apriboti iki .php. Tai pagauna žiniatinklio serverio konfigūracijos klaidas, bet jos nepakeičia.

Ar Nginx taisyklės yra apsauga nuo PHP2Shell?

Ne. PHP2Shell slypi PHP interpretatoriuje ir uždaroma tik atnaujinus į ištaisytą versiją ir iš naujo paleidus visus darbinius procesus (worker). Saugi Nginx konfigūracija sumažina atakos paviršių ir apriboja žalą po įsilaužimo.

Šaltiniai

Skubus kontaktas

Kiekviena valanda svarbi. Parašykite mums dabar.

Trumpai aprašykite sistemą, PHP versiją ir pastebėjimus. Mes atsakysime, išsiaiškinsime padėtį ir dirbsime nuotoliu, kol incidentas bus užbaigtas ir dokumentuotas.

Skubi pagalba