# Nginx ja PHP-FPM turvalliseksi

> Nginx PHP-FPM tietoturva PHP2Shellin jälkeen: tarkista poolit ja versiot, käynnistä kaikki worker-prosessit uudelleen, aseta väliaikaiset arvot ja koventa Nginx.

Lähde: https://phpsos.de/fi/server/nginx-php-fpm/  
Tilanne: 25.10.2026  
Palveluntarjoaja: PHP SOS, PHP-hätäapu ja palvelimen tietoturva. Pikaapu WhatsAppilla: https://wa.me/491736494914?text=Hei%20PHP%20SOS%2C%20tarvitsemme%20apua%20PHP-palvelimemme%20kanssa.%20Yritys%3A%20%E2%80%A6%20Verkkosivusto%3A%20%E2%80%A6

**Lyhyesti:** Nginxilla ja PHP-FPM:llä PHP2Shellin haavoittuvuus on PHP-FPM:ssä, ei Nginxissä. Korjaa kaikki PHP-FPM-versiot, käynnistä jokainen FPM-palvelu kokonaan uudelleen ja todista se prosessien käynnistysajoilla. Nginxin ja PHP-FPM:n tietoturvan kannalta pitkällä aikavälillä ratkaisevat erilliset poolit, ylikirjoittamattomat arvot ja Nginx-konfiguraatio, joka ei suorita ladattuja tiedostoja.

## Miten Nginx ja PHP-FPM toimivat yhdessä

Nginx tarjoaa staattiset tiedostot itse ja välittää PHP-skriptien pyynnöt FastCGI:n kautta PHP-FPM:lle. PHP-FPM koostuu master-prosessista ja useista worker-prosesseista, jotka on ryhmitelty pooleihin. Yksi worker käsittelee peräkkäin monta pyyntöä.

Juuri tämä on PHP2Shellin kannalta olennaista. Haavoittuvuudessa CVE-2026-109619 pyynnön sisäinen tila voi jäädä voimaan muistin vapauttamisen jälkeen ja myöhempi pyyntö samassa workerissa voi hyödyntää sitä. Haavoittuvuudessa CVE-2026-109618 muistin loppuminen (Out of Memory) voi keskeyttää PHP:n kesken pyynnön alustuksen. Molemmat on arvioitu CVSS v4.0 -pisteillä 9.2, ja ne on korjattu versioissa PHP 8.5.12, 8.4.27, 8.3.36 ja 8.2.35.

## Tarkista kanta: versiot, poolit, prosessit

Monilla palvelimilla on useita PHP-FPM-versioita rinnakkain. Seuraavat komennot vain lukevat; paketti- ja palvelunimet ovat esimerkkejä Debianille/Ubuntulle ja RHEL-perheelle.

```bash
# Mitkä FPM-palvelut pyörivät?
systemctl list-units --type=service | grep -i fpm

# Mikä versio niiden takana on? (esimerkki Debian/Ubuntu)
php-fpm8.3 -v
# RHEL-perhe
php-fpm -v

# Mihin sockettiin tai porttiin Nginx välittää?
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'

# Poolit ja niiden käyttäjät
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null
```

Vertaa jokaista `fastcgi_pass`-merkintää käynnissä olevaan pooliin. Näin näet, mikä PHP-versio palvelee mitäkin verkkosivustoa. Jakelupaketeissa korjauksen todistaa muutosloki CVE-numeroineen, ei pelkkä versionumero.

Tällaisissa kartoituksissa yleinen löydös ovat palvelimet, joille on vuosien varrella asennettu useita PHP-versioita ja joista vain yksi on todella käytössä. Muut FPM-palvelut pyörivät silti edelleen, usein oletuspooleilla, jotka kuuntelevat paikallista socketia tai porttia. Ne eivät yleensä ole suoraan tavoitettavissa ulkopuolelta, mutta ovat turha riski ja pidentävät jokaista hätäpäivitystä. Poista käytöstä ja asennuksesta versiot, joita mikään verkkosivusto ei käytä, kun olet tarkistanut liitokset `fastcgi_pass`-merkintöjen kautta.

Yhtä lailla kannattaa katsoa poolien käyttäjää. Jos kaikki poolit toimivat käyttäjänä `www-data` tai `nginx`, verkkosivustojen erotus on olemassa vain paperilla. Joka ottaa yhden verkkosivuston haltuunsa, voi silloin lukea kaikkien muiden tiedostot, esimerkiksi konfiguraatiotiedostot tietokannan salasanoineen. Omat järjestelmäkäyttäjät poolia kohden ja sopivat tiedosto-oikeudet luovat tähän todellisen rajan. Se ei ole korjaus PHP2Shelliin, mutta rajoittaa onnistuneen hyökkäyksen mahdollista vahinkoa selvästi.

## Asenna korjaus ja uusi kaikki workerit

Paketin päivityksen jälkeen käynnistä jokainen PHP-FPM-palvelu uudelleen. Reload korvaa workerit, mutta täysi uudelleenkäynnistys uusii myös master-prosessin ja on tietoturvapäivitysten jälkeen varma tapa.

```bash
# Esimerkki Debian/Ubuntu, jokaiselle asennetulle versiolle
systemctl restart php8.3-fpm
# RHEL-perhe
systemctl restart php-fpm

# Tarkistus: masterin ja workerien käynnistysaika
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep
```

Jokaisen prosessin on oltava käynnistetty päivityksen jälkeen. Asia on kuvattu tarkemmin sivulla [PHP-FPM ja kaikki worker-prosessit uudelleen](https://phpsos.de/fi/php2shell/php-fpm-neustart/).

> **Tärkeää:**
> Korjaus ei poista haittaohjelmaa, joka on asennettu aiemmin. Säilytä Nginxin käyttö- ja virhelokit 20.10.2026 alkaen ja tarkista verkkosivustojen jäljet.

## Aseta väliaikaiset arvot poolissa

Niin kauan kuin versiota ei ole korjattu, php.net suosittelee väliaikaisia toimenpiteitä. Ne eivät tarjoa täydellistä suojaa. PHP-FPM:ssä arvot asetetaan poolissa `php_admin_value`- tai `php_admin_flag`-direktiiveillä, jolloin sovellukset eivät voi ylikirjoittaa niitä `ini_set()`-kutsulla.

```ini
; Esimerkki: /etc/php/8.3/fpm/pool.d/website.conf
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 24M
```

Ilman latausominaisuutta php.net mainitsee arvon `post_max_size = 8M`. PHP 8.5:ssä lisätään `fatal_error_backtraces=0`. Ohjetta `memory_limit=-1` varten tarvitset cgroup-tason muistirajan, esimerkiksi `MemoryMax`-asetuksella FPM-palvelun systemd-lisäyksessä. Sovita Nginxissä `client_max_body_size` uuteen `post_max_size`-arvoon, jotta käyttäjät saavat ymmärrettäviä virheilmoituksia. Sen jälkeen käynnistä FPM uudelleen.

## Nginxin ja PHP-FPM:n tietoturvan pysyvä parantaminen

Akuutin tapauksen jälkeen muutama perussääntö auttaa rajoittamaan vahinkoa tulevissa haavoittuvuuksissa:

- **Yksi pooli per verkkosivusto** omalla järjestelmäkäyttäjällä, omalla socketilla ja omalla `open_basedir`-rajalla. Lisää sivulla [open_basedir ja sivustokohtainen eristys](https://phpsos.de/fi/ratgeber/open-basedir/).
- **Socketin oikeudet** niin, että vain Nginx pääsee käsiksi, älä avaa FPM-portteja ulospäin.
- **Suorita vain olemassa olevat skriptit:** aseta PHP-locationiin `try_files $uri =404;`, jotta Nginx ei välitä PHP:lle polkuja, joita ei ole.
- **Älä suorita latauksia:** kiellä PHP:n suoritus latauskansioissa. Vihjeitä on sivulla [Tiedostolataukset turvallisiksi](https://phpsos.de/fi/ratgeber/datei-upload-sicher/).
- **Suojaa tilasivut:** tee `pm.status_path` ja `ping.path` tavoitettaviksi vain sisäisesti.

```nginx
# Esimerkki: ei PHP:n suoritusta latauskansiossa
location ~* ^/uploads/.*\.php$ {
    deny all;
}
```

Tarkista jokainen muutos komennolla `nginx -t`, ennen kuin lataat Nginxin uudelleen. Kirjaa lisäksi ylös, mitä pooleja, versioita ja erityissääntöjä palvelimella on. Tämä lyhyt dokumentaatio säästää arvokasta aikaa seuraavan kriittisen haavoittuvuuden kohdalla, koska kenenkään ei tarvitse ensin etsiä, mikä verkkosivusto kuuluu mihinkin pooliin.

## Miten PHP SOS auttaa konkreettisesti?

- Yhdistämme jokaisen verkkosivuston pooliinsa ja PHP-versioonsa ja tarkistamme todellisen pakettitilan.
- Korjaamme, käynnistämme kaikki FPM-palvelut uudelleen ja dokumentoimme prosessien käynnistysajat todisteeksi.
- Korjaukseen asti asetamme väliaikaiset arvot poolikohtaisesti ja rajoitamme muistin cgroupilla.
- [Palvelimen koventamisen](https://phpsos.de/fi/leistungen/server-haertung/) puitteissa erotamme poolit, oikeudet ja latauskansiot siististi.
- Murtoepäilyn tapauksessa hoidamme [poikkeamien hallinnan](https://phpsos.de/fi/leistungen/incident-response/).


## Usein kysytyt kysymykset

**Riittääkö systemctl reload PHP-FPM:lle päivityksen jälkeen?**  
Reload uusii worker-prosessit, mutta master-prosessi voi säilyttää vanhan koodin. Tietoturvapäivityksen jälkeen palvelun täysi uudelleenkäynnistys on varma tapa. Tarkista sen jälkeen masterin ja workerien käynnistysaika.

**Pitääkö Nginx käynnistää uudelleen PHP-päivityksen jälkeen?**  
Nginx ei sisällä PHP:tä, eikä sitä tarvitse käynnistää uudelleen PHP-korjauksen vuoksi. Uudelleen on käynnistettävä kaikki PHP-FPM-palvelut. Jos muutat samalla Nginxin konfiguraatiota, tarkista se ennen uudelleenlatausta komennolla nginx -t.

**Miksi jokaiselle verkkosivustolle oma pooli?**  
Jokainen pooli toimii omalla käyttäjällään ja omilla rajoillaan. Jos yksi verkkosivusto vaarantuu, hyökkääjä ei pääse helposti muiden tiedostoihin. Lisäksi väliaikaiset arvot voi asettaa kohdennetusti poolikohtaisesti.

**Onko pm.max_requests suoja PHP2Shelliä vastaan?**  
Ei, se ei korvaa korjausta. Arvo rajoittaa, kuinka monta pyyntöä worker käsittelee ennen kuin se korvataan. Se voi lyhentää tilojen elinikää prosessissa, mutta se ei ole php.net:n mainitsema korjaustoimenpide.

## Lähteet

- [php.net: tietoturvatiedotteet](https://www.php.net/)
- [PHP 8 ChangeLog (muutosloki)](https://www.php.net/ChangeLog-8.php)
- [OWASP Cheat Sheets (ohjekortit)](https://cheatsheetseries.owasp.org/)
- [BSI (Saksan liittovaltion tietoturvavirasto)](https://www.bsi.bund.de/)
