Em resumo: O CGI (Common Gateway Interface) é uma interface antiga em que o servidor web inicia um programa novo para cada pedido, no caso do PHP o programa php-cgi. O FastCGI é a evolução: os processos PHP correm de forma permanente e aceitam muitos pedidos através de um socket. O PHP-FPM é a implementação FastCGI mais importante para o PHP. Relevantes para a segurança são sobretudo as definições cgi.* e a regra de que um acesso FastCGI nunca pode ser publicamente acessível.
O que é o CGI?
O CGI é um dos métodos mais antigos com que os servidores web geram conteúdos dinâmicos. O manual do PHP remete, na definição cgi.rfc2616_headers, para o RFC 3875, a especificação do Common Gateway Interface. Também os primórdios do PHP eram programas CGI: Rasmus Lerdorf escreveu em 1994 as primeiras «Personal Home Page Tools» como binários CGI em C.
O princípio: para cada pedido, o servidor web inicia um processo novo, passa os dados do pedido através de variáveis de ambiente e da entrada padrão e lê a resposta da saída padrão. Depois, o processo termina. Segundo o manual do PHP, no CGI e na CLI o PHP volta a ler o seu php.ini a cada chamada, nos módulos de servidor apenas no arranque.
Isto torna o CGI robusto, porque cada pedido começa com um processo novo. Mas também o torna lento: iniciar o processo, carregar a configuração e inicializar as extensões custam tempo a cada pedido.
O que é o FastCGI?
O FastCGI resolve o problema de desempenho mantendo os processos vivos. O servidor web liga-se, através de um socket Unix ou de uma porta TCP, a um processo em execução e envia-lhe o pedido no protocolo FastCGI. O processo trata-o e espera pelo seguinte.
| Característica | CGI | FastCGI com php-cgi | FastCGI com PHP-FPM |
|---|---|---|---|
| Processo por pedido | sim | não | não |
| Nome da SAPI | cgi-fcgi |
cgi-fcgi |
fpm-fcgi |
| Pools com utilizador próprio | não | não | sim |
| Controlo de processos | servidor web | módulo do servidor web, p. ex. mod_fcgid | processo mestre próprio |
O .user.ini é lido |
sim | sim | sim |
Segundo o manual, o PHP-FPM é a implementação FastCGI principal do PHP. Complementa o protocolo com gestão de processos, pools, páginas de estado e um slowlog. Os pormenores estão em PHP-FPM explicado.
As definições cgi no php.ini
Para o funcionamento em CGI, o PHP conhece definições próprias. Os valores e descrições seguintes provêm do manual do PHP:
cgi.force_redirect(por defeito 1,INI_SYSTEM): segundo o manual, necessário para operar o PHP como CGI em segurança na maioria dos servidores web. Desligar apenas «por sua conta e risco»; no IIS tem de estar desligado.cgi.fix_pathinfo(por defeito 1,INI_SYSTEM): assegura valores corretos dePATH_INFOePATH_TRANSLATED. Os scripts devem usarSCRIPT_FILENAMEem vez dePATH_TRANSLATED.cgi.discard_path(por defeito 0,INI_SYSTEM): permite guardar o binário CGI em segurança fora da pasta web, sem que a proteção do.htaccesspossa ser contornada.fastcgi.impersonate(por defeito 0,INI_SYSTEM): relevante apenas para o IIS no Windows.user_ini.filenameeuser_ini.cache_ttl(por defeito.user.inie 300 segundos): controlam se e com que frequência o PHP lê ficheiros.user.ini.
No Nginx, faz parte disto uma passagem correta do caminho do script. Um modelo de base legível, sem garantia para todos os ambientes:
location ~ \.php$ {
try_files $uri =404; # só passar ao PHP ficheiros existentes
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
A linha try_files $uri =404; impede que pedidos para caminhos .php inexistentes sejam passados ao PHP.
Porque é que um acesso FastCGI aberto é perigoso
O manual do PHP avisa expressamente: quem consegue abrir uma ligação FastCGI ao PHP controla a configuração do pedido, por exemplo auto_prepend_file, e pode assim executar código arbitrário. A razão é que os servidores web podem enviar definições do PHP através de parâmetros FastCGI como PHP_VALUE e PHP_ADMIN_VALUE.
Daqui resultam regras claras:
- Ligar o PHP-FPM ou o php-cgi em modo FastCGI apenas através de um socket Unix, quando o servidor web corre no mesmo anfitrião.
- Com TCP, definir
listen.allowed_clientse bloquear a porta na firewall; indicações no artigo Firewall para servidores web. - Manter restritas as permissões do socket com
listen.owner,listen.groupelisten.mode.
Verifique com ss -lntp | grep -i php se algum processo PHP está à escuta num endereço TCP. Uma ligação a 0.0.0.0 ou a um endereço público é um caso urgente de intervenção.
CGI, FastCGI e PHP2Shell
O PHP2Shell afeta tanto o php-cgi como o PHP-FPM. Para ambos vale: atualização para 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, ou um backport confirmado, e depois terminar e reiniciar todos os processos PHP em execução. Em configurações FastCGI com php-cgi, os processos muitas vezes continuam a correr sem darem nas vistas, porque nenhum serviço próprio os gere. Como encontrar e substituir este legado explica-o php-cgi: legado com risco. No Plesk, as variantes têm outros nomes; ajuda Plesk: compreender os handlers PHP.
Como ajuda concretamente a PHP SOS?
- Levantar os handlers: Apuramos se os seus sites correm via CGI, FastCGI com php-cgi ou PHP-FPM.
- Fechar acessos: Verificamos sockets, portas e regras de firewall, para que nenhum acesso FastCGI seja acessível a partir do exterior.
- Aplicar patches e limpar: Atualizamos o PHP e terminamos todos os processos antigos, também as instâncias órfãs do php-cgi.
- Substituir: No âmbito do reforço de servidores, substituímos o legado CGI por PHP-FPM com pools próprios.
Perguntas frequentes
O FastCGI é o mesmo que o PHP-FPM?
Não. O FastCGI é um protocolo através do qual um servidor web fala com um processo de aplicação. O PHP-FPM é um programa que implementa esse protocolo para o PHP e gere os processos. O php-cgi também pode falar FastCGI, mas não oferece pools.
Porque é que o CGI puro é considerado obsoleto?
No CGI, o servidor web inicia um processo novo para cada pedido e o PHP lê de cada vez a sua configuração. Isso custa tempo e recursos. O FastCGI e o PHP-FPM mantêm processos permanentemente prontos e são, por isso, claramente mais eficientes.
O que é um .user.ini?
Um .user.ini é um pequeno ficheiro de configuração numa pasta web. Segundo o manual do PHP, só é lido pelas SAPI de CGI e FastCGI, ou seja, também pelo PHP-FPM. Só pode conter definições com os modos INI_PERDIR, INI_USER ou INI_ALL.
Como sei se no meu servidor corre o php-cgi?
Procure, com comandos de leitura como ps ou pgrep, processos com o nome php-cgi e veja na configuração do servidor web entradas como mod_fcgid, Action ou ScriptAlias com php-cgi. Nos painéis de alojamento, o modo de operação chama-se muitas vezes CGI ou aplicação FastCGI.