# Proibir a execução de PHP em pastas de uploads

> Proibir a execução de PHP em uploads: encontrar pastas com escrita, definir bloqueios no Nginx, Apache e PHP-FPM e testar com um ficheiro inofensivo.

Fonte: https://phpsos.de/pt/blog/php-in-uploads-verbieten/  
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:** Para proibir a execução de PHP em uploads, determine primeiro todas as pastas em que o PHP pode escrever e bloqueie depois, em cada uma delas, a execução de scripts na configuração do servidor, não por `.htaccess`. No Nginx, o bloqueio tem de atuar antes do bloco PHP geral; no Apache, pertence ao VirtualHost com `AllowOverride None`. `security.limit_extensions = .php` no pool FPM e um teste com um ficheiro inofensivo concluem o trabalho.

## Por que razão as pastas de uploads contam precisamente agora

Após uma vulnerabilidade crítica como o PHP2Shell, os atacantes raramente querem executar código apenas uma vez. Querem regressar, mesmo que o servidor seja corrigido mais tarde. O caminho mais simples para isso é uma webshell: um pequeno ficheiro PHP, colocado numa pasta com permissão de escrita e chamado mais tarde através do navegador.

Um patch não remove um ficheiro destes. Quem esteve online sem patch a partir de 20 de outubro de 2026 deve, por isso, não só atualizar, mas também verificar se há novos ficheiros PHP em algum lado e impedir daqui em diante que sejam executados. Como interpretar as ocorrências é descrito em [Ficheiros PHP na pasta de uploads: interpretar corretamente as ocorrências](https://phpsos.de/pt/blog/php-dateien-im-upload-ordner/).

O bloqueio de execução atua sobre a segunda condição. Não impede que um ficheiro seja colocado, mas que o servidor o trate como programa.

## Primeiro o inventário: onde pode o PHP escrever?

A maioria dos guias refere apenas a pasta de uploads. Na prática, uma aplicação PHP escreve em muito mais sítios. Cada um deles que seja acessível através do servidor web precisa do bloqueio.

| Tipo de pasta | Conteúdo típico | Por que tem escrita |
|---|---|---|
| Uploads, multimédia | imagens, PDF, anexos | utilizadores e redação carregam ficheiros |
| Cache | páginas geradas, miniaturas | a aplicação acelera a entrega |
| Temporários, importação, exportação | ficheiros CSV, estados intermédios | interfaces e troca de dados |
| Cópias de segurança na raiz web | `.zip`, `.sql` | extensões guardam «no local» |
| Registos na raiz web | registos de erros e de depuração | aplicações mal configuradas |

As pastas que isto significa no seu servidor são mostradas por uma pesquisa com os direitos do utilizador de execução. Não altera nada:

```bash
# Todas as pastas sob /var/www em que o utilizador do PHP pode escrever
# (adaptar o utilizador: www-data, nginx, apache ou utilizador próprio do pool)
sudo -u www-data find /var/www -type d -writable 2>/dev/null | sort
# Já existem ficheiros PHP nestas pastas?
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
```

Se a primeira pesquisa devolver toda a raiz web, o código do programa pertence ao utilizador de execução. Deve alterá-lo antes, como descreve o guia [Permissões de ficheiros no servidor web](https://phpsos.de/pt/ratgeber/dateirechte-webserver/). Caso contrário, não há nenhuma pasta que não precise de ser bloqueada.

## Proibir a execução de PHP em uploads: Nginx

No Nginx, a ordem decide. Segundo a documentação do Nginx, as expressões regulares são verificadas pela ordem do ficheiro de configuração, e ganha a primeira correspondência. Se o bloco geral `location ~ \.php$` estiver antes do seu bloqueio, o ficheiro é executado. Uma location de prefixo simples, sem `^~`, não protege pela mesma razão.

Seguro é uma expressão regular para todas as pastas bloqueadas, colocada antes do bloco PHP. Cobre também extensões raramente usadas:

```nginx
server {
    # ... configuração de base ...

    # 1. Bloqueio para pastas com escrita, TEM de estar antes do bloco PHP
    location ~* ^/(uploads|media|cache|tmp|export)/.*\.(php\d?|phtml|phar|pht|phps)$ {
        deny all;
    }

    # 2. Bloco PHP geral: passar apenas ficheiros existentes
    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;
    }
}
```

Adapte os nomes das pastas ao seu inventário. Em aplicações com um único ponto de entrada, o caminho por uma lista de permissões é ainda mais forte; o modelo está em [Configurar o Nginx para PHP com segurança](https://phpsos.de/pt/blog/nginx-fuer-php-absichern/).

## Apache e PHP-FPM: o bloqueio no sítio certo

No Apache, o bloqueio pertence à configuração do servidor ou ao VirtualHost. Um `.htaccess` na pasta de uploads é inadequado, porque qualquer pessoa com escrita nessa pasta o pode alterar. Para toda a raiz web aplica-se, por isso, `AllowOverride None`. Segundo a documentação do Apache, o `AllowOverride` só é permitido em blocos `<Directory>` sem expressões regulares; defina-o, portanto, na raiz web e o bloqueio por `<DirectoryMatch>` por baixo:

```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>
```

Se ainda correr o mod_php, acrescente no mesmo bloco `php_admin_flag engine off`. No PHP-FPM, atua uma segunda barreira no pool: o `security.limit_extensions` determina que extensões o FPM executa. Segundo o manual do PHP, o valor por defeito é `.php .phar`; recomenda-se a restrição a `.php`.

```ini
; no pool, p. ex. /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
```

## Testar com um ficheiro inofensivo

Se o bloqueio funciona, só um teste o mostra. Coloque por breves instantes em cada pasta bloqueada um ficheiro que apenas apresente um texto, chame-o através do domínio e elimine-o depois.

1. Verificar a configuração: `nginx -t` ou `apachectl configtest`, depois recarregar.
2. Criar o ficheiro de teste, por exemplo `uploads/sperrtest.php` com o conteúdo `<?php echo 'ausgefuehrt';`.
3. Chamar com `curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/uploads/sperrtest.php`. Espera-se `403`.
4. Se, em vez disso, aparecer `200` e o texto «ausgefuehrt», o bloqueio não atua. Verificar configuração e ordem.
5. Eliminar o ficheiro de teste e repetir o teste para cada pasta e cada site.

> **Importante:**
> Se, no inventário, encontrar já ficheiros PHP desconhecidos em pastas com escrita, não elimine nada precipitadamente. Preserve primeiro o estado e os registos, pois esses ficheiros são meios de prova. Como proceder depois é descrito em [Reconhecer e remover webshells](https://phpsos.de/pt/ratgeber/webshell-erkennen/).

Como se constroem com segurança as funções de upload no código, com verificação de tipo e armazenamento fora da raiz web, está no guia [Implementar uploads de ficheiros em PHP com segurança](https://phpsos.de/pt/ratgeber/datei-upload-sicher/).

## Conclusão: escrever sim, executar não

O bloqueio de execução em pastas com escrita é uma das medidas isoladas mais eficazes contra portas dos fundos permanentes. Custa poucas linhas de configuração e não estraga nada em aplicações bem construídas. Três coisas são decisivas: um inventário completo, em vez de apenas a pasta de uploads óbvia, a ordem correta no Nginx ou o nível correto no Apache e um teste real com um ficheiro inofensivo.

Complementado por proprietários separados para o código do programa, `security.limit_extensions` no pool e uma pesquisa regular de novos ficheiros PHP, chega-se a um estado em que um ficheiro colocado é irritante, mas dificilmente utilizável. Isto não substitui a atualização nem a pesquisa de vestígios, mas retira aos atacantes uma das suas ferramentas mais importantes.

## Como ajuda concretamente a PHP SOS?

- **Inventário:** determinamos todas as pastas com escrita por site e verificamos se já contêm ficheiros PHP.
- **Definir bloqueios:** registamos os bloqueios de execução no Nginx, no Apache e no PHP-FPM, na ordem certa e sem dependência do `.htaccess`.
- **Testar:** verificamos cada bloqueio com um ficheiro inofensivo e documentamos o resultado.
- **Limpar:** perante ocorrências, assumimos a preservação de vestígios e a [remoção de malware](https://phpsos.de/pt/leistungen/malware-entfernung/).


## Perguntas frequentes

**Basta um .htaccess na pasta de uploads para proibir o PHP?**  
Não de forma fiável. Quem pode escrever na pasta pode também alterar ou substituir o .htaccess. O bloqueio pertence à configuração do servidor ou ao VirtualHost e, para a raiz web, deve aplicar-se AllowOverride None.

**Que pastas tenho de bloquear?**  
Todas as pastas em que o utilizador do PHP pode escrever e que são acessíveis através do servidor web. Além das pastas de uploads, são muitas vezes diretórios de cache, temporários, de importação, de exportação e de cópias de segurança. Determine-as com uma pesquisa feita como utilizador de execução.

**O bloqueio estraga o meu site?**  
Em regra, não, pois nas pastas de uploads e de cache de aplicações bem construídas não há scripts chamados diretamente. Algumas extensões colocam, no entanto, ficheiros PHP aí. Por isso, teste as funções mais importantes depois da alteração.

**O bloqueio protege contra o PHP2Shell?**  
Não. O PHP2Shell é uma vulnerabilidade no interpretador PHP, que só se fecha com a atualização e o reinício de todos os workers. O bloqueio impede, no entanto, que um ficheiro colocado seja mais tarde chamado através do navegador e usado como porta dos fundos permanente.

## Fontes

- [Nginx: seleção dos blocos location](https://nginx.org/en/docs/http/ngx_http_core_module.html)
- [Apache: funcionalidades centrais (AllowOverride, FilesMatch)](https://httpd.apache.org/docs/2.4/mod/core.html)
- [Manual do PHP: configuração do FPM (security.limit_extensions)](https://www.php.net/manual/en/install.fpm.configuration.php)
- [OWASP Cheat Sheets (File Upload)](https://cheatsheetseries.owasp.org/)
