# Proteger o Nginx com PHP-FPM

> Segurança Nginx PHP-FPM após o PHP2Shell: verificar pools e versões, reiniciar todos os workers, definir valores provisórios com php_admin_value e reforçar o Nginx.

Fonte: https://phpsos.de/pt/server/nginx-php-fpm/  
Atualizado em: 25/10/2026  
Prestador: PHP SOS, Assistência de emergência PHP e segurança de servidores. Ajuda imediata por WhatsApp: https://wa.me/491736494914?text=Ol%C3%A1%2C%20PHP%20SOS%2C%20precisamos%20de%20ajuda%20com%20o%20nosso%20servidor%20PHP.%20Empresa%3A%20%E2%80%A6%20Site%3A%20%E2%80%A6

**Em resumo:** no Nginx com PHP-FPM, a vulnerabilidade do PHP2Shell está no PHP-FPM, não no Nginx. Aplique o patch a todas as versões de PHP-FPM, reinicie por completo cada serviço FPM e comprove-o com as horas de arranque dos processos. Para a segurança duradoura do Nginx com PHP-FPM contam pools separados, valores que não podem ser sobrescritos e uma configuração do Nginx que não execute ficheiros carregados.

## Como o Nginx e o PHP-FPM trabalham em conjunto

O Nginx entrega ficheiros estáticos por si próprio e reencaminha os pedidos a scripts PHP para o PHP-FPM através de FastCGI. O PHP-FPM é composto por um processo master e vários processos worker, agrupados em pools. Um worker trata muitos pedidos em sequência.

É precisamente isso que é relevante para o PHP2Shell. Na CVE-2026-109619, o estado interno de um pedido pode persistir depois de a memória ser libertada e ser usado por um pedido posterior no mesmo worker. Na CVE-2026-109618, uma situação de falta de memória pode interromper o PHP a meio da inicialização de um pedido. Ambas as vulnerabilidades têm a pontuação CVSS v4.0 9.2 e estão corrigidas no PHP 8.5.12, 8.4.27, 8.3.36 e 8.2.35.

## Verificar o inventário: versões, pools, processos

Muitos servidores têm várias versões de PHP-FPM em paralelo. Os comandos seguintes apenas leem; os nomes de pacotes e de serviços são exemplos para Debian/Ubuntu e para a família RHEL.

```bash
# Que serviços FPM estão a correr?
systemctl list-units --type=service | grep -i fpm

# Que versão está por trás? (exemplo Debian/Ubuntu)
php-fpm8.3 -v
# Família RHEL
php-fpm -v

# Para que sockets ou portas reencaminha o Nginx?
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'

# Pools e os seus utilizadores
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null
```

Compare cada entrada `fastcgi_pass` com um pool em execução. Assim vê que versão PHP serve que site. Nos pacotes das distribuições, é o registo de alterações com os números CVE que comprova o patch, não apenas o número de versão.

Um achado frequente nestes levantamentos são servidores em que, ao longo dos anos, foram instaladas várias versões PHP, das quais só uma está realmente em uso. Os restantes serviços FPM continuam a correr na mesma, muitas vezes com pools padrão que escutam num socket ou porta local. Do exterior, normalmente não são diretamente acessíveis, mas continuam a ser um risco desnecessário e prolongam qualquer atualização de emergência. Desative e remova as versões que nenhum site usa, depois de verificar a atribuição através das entradas `fastcgi_pass`.

Vale igualmente a pena olhar para o utilizador dos pools. Se todos os pools correrem como `www-data` ou `nginx`, a separação entre os sites existe apenas no papel. Quem tomar conta de um site pode então ler os ficheiros de todos os outros, por exemplo ficheiros de configuração com palavras-passe de bases de dados. Utilizadores de sistema próprios por pool e permissões de ficheiros adequadas criam aqui uma fronteira real. Isto não é uma mitigação para o PHP2Shell, mas limita claramente os danos possíveis de um ataque bem-sucedido.

## Instalar o patch e renovar todos os workers

Depois da atualização dos pacotes, reinicie cada serviço PHP-FPM. Um reload substitui os workers, mas um reinício completo renova também o processo master e é o caminho seguro depois de atualizações de segurança.

```bash
# Exemplo Debian/Ubuntu, por versão instalada
systemctl restart php8.3-fpm
# Família RHEL
systemctl restart php-fpm

# Verificação: hora de arranque do master e dos workers
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep
```

Todos os processos têm de ter sido iniciados depois da atualização. Está descrito em pormenor em [Reiniciar o PHP-FPM e todos os workers](https://phpsos.de/pt/php2shell/php-fpm-neustart/).

> **Importante:**
> Um patch não remove software malicioso introduzido antes. Guarde os registos de acesso e de erros do Nginx a partir de 20/10/2026 e verifique se os sites apresentam vestígios.

## Definir valores provisórios no pool

Enquanto uma versão não tiver patch, o php.net recomenda medidas provisórias. Não oferecem proteção completa. No PHP-FPM, defina os valores com `php_admin_value` ou `php_admin_flag` no pool; assim, as aplicações não os podem sobrescrever com `ini_set()`.

```ini
; Exemplo: /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
```

Sem função de upload, o php.net indica `post_max_size = 8M`. No PHP 8.5 acresce `fatal_error_backtraces=0`. Para a indicação sobre `memory_limit=-1` precisa de um limite de memória ao nível do cgroup, por exemplo através de `MemoryMax` num complemento do systemd para o serviço FPM. Ajuste no Nginx o `client_max_body_size` ao novo `post_max_size`, para que os utilizadores recebam mensagens de erro compreensíveis. Depois, reinicie o FPM.

## Melhorar de forma duradoura a segurança do Nginx com PHP-FPM

Para além do caso agudo, ajudam algumas regras básicas que limitam os danos em futuras vulnerabilidades:

- **Um pool por site**, com utilizador de sistema próprio, socket próprio e limite `open_basedir` próprio. Mais em [open_basedir e isolamento por site](https://phpsos.de/pt/ratgeber/open-basedir/).
- **Permissões do socket** definidas de modo a que apenas o Nginx possa aceder; não abrir portas FPM para o exterior.
- **Executar apenas scripts existentes:** na location do PHP, definir `try_files $uri =404;`, para que o Nginx não passe ao PHP caminhos que não existem.
- **Não executar uploads:** proibir a execução de PHP nos diretórios de upload. Há indicações em [Implementar uploads de ficheiros em segurança](https://phpsos.de/pt/ratgeber/datei-upload-sicher/).
- **Proteger as páginas de estado:** tornar `pm.status_path` e `ping.path` acessíveis apenas internamente.

```nginx
# Exemplo: sem execução de PHP no diretório de uploads
location ~* ^/uploads/.*\.php$ {
    deny all;
}
```

Verifique cada alteração com `nginx -t` antes de recarregar o Nginx. Registe também que pools, versões e regras especiais existem no servidor. Esta breve documentação poupa tempo precioso na próxima vulnerabilidade crítica, porque ninguém tem de começar por procurar que site está ligado a que pool.

## Como ajuda concretamente a PHP SOS?

- Associamos cada site ao seu pool e à sua versão PHP e verificamos o nível real dos pacotes.
- Aplicamos o patch, reiniciamos todos os serviços FPM e documentamos as horas de arranque dos processos como comprovativo.
- Até ao patch, definimos os valores provisórios por pool e limitamos a memória por cgroup.
- No âmbito do [reforço de servidores](https://phpsos.de/pt/leistungen/server-haertung/), separamos de forma limpa pools, permissões e diretórios de upload.
- Em caso de suspeita de intrusão, assumimos a [resposta a incidentes](https://phpsos.de/pt/leistungen/incident-response/).


## Perguntas frequentes

**Basta systemctl reload para o PHP-FPM depois de uma atualização?**  
Um reload renova os workers, mas o processo master pode manter o código antigo. Depois de uma atualização de segurança, o caminho seguro é um reinício completo do serviço. Verifique a seguir a hora de arranque do master e dos workers.

**O Nginx tem de ser reiniciado depois de uma atualização do PHP?**  
O próprio Nginx não contém PHP e não precisa de reiniciar para o patch do PHP. Têm de reiniciar todos os serviços PHP-FPM. Se alterar entretanto a configuração do Nginx, verifique-a com nginx -t antes de a recarregar.

**Porquê pools separados por site?**  
Cada pool corre com o seu próprio utilizador e os seus próprios limites. Se um site for comprometido, o atacante não chega sem mais aos ficheiros dos outros. Além disso, os valores provisórios podem ser definidos de forma dirigida por pool.

**O pm.max_requests é uma proteção contra o PHP2Shell?**  
Não, não substitui um patch. O valor limita quantos pedidos um worker trata antes de ser substituído. Isso pode encurtar a duração de vida de estados no processo, mas não é uma medida de mitigação indicada pelo php.net.

## Fontes

- [php.net: avisos de segurança](https://www.php.net/)
- [PHP 8 ChangeLog](https://www.php.net/ChangeLog-8.php)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
- [BSI (Gabinete Federal Alemão para a Segurança da Informação)](https://www.bsi.bund.de/)
