Situação atual: PHP2Shell. Duas vulnerabilidades críticas do PHP (CVSS 9,2) permitem executar código malicioso sem autenticação. Patches disponíveis desde 21/10/2026.O que fazer agora →

Evitar Local File Inclusion em PHP: LFI e RFI

Quando o include ou o require aceitam caminhos do pedido, os atacantes podem carregar ficheiros alheios. Como construir com segurança a seleção de páginas e os modelos e proteger adicionalmente o servidor.

Atualizado em 6 min de leituraGuias

Em resumo: a Local File Inclusion em PHP surge quando include, require ou funções de ficheiros usam um caminho que o visitante pode influenciar. A solução segura é uma lista de permissão fixa: o parâmetro escolhe apenas entre valores conhecidos, e o próprio caminho nunca vem do pedido. Do lado do servidor, allow_url_include=Off, open_basedir e permissões de ficheiros restritivas completam a proteção.

O que é a Local File Inclusion em PHP?

Muitas aplicações PHP mais antigas carregam páginas segundo um padrão simples: um parâmetro no endereço determina que ficheiro é incluído. Se esse parâmetro for passado sem verificação ao include, um atacante pode pedir outros ficheiros do servidor. No caso mais benigno, lê ficheiros de configuração com credenciais. No pior caso, leva o PHP a executar conteúdos que antes colocou noutro local, por exemplo num upload ou num ficheiro de registo.

Para a gestão, é importante: esta vulnerabilidade raramente está no núcleo do CMS, mas sobretudo em desenvolvimentos próprios, extensões antigas ou páginas adicionais construídas à pressa. No dia a dia não se nota, porque o site funciona normalmente.

Na Remote File Inclusion, o PHP carrega código de um endereço alheio. Isto pressupõe que o allow_url_include esteja ativado. Nas versões atuais do PHP, esta definição vem desativada por defeito, mas ainda se encontra em servidores antigos ou mal configurados.

Padrões vulneráveis típicos no código

Estão em risco os pontos em que um valor do pedido, de cookies ou da base de dados passa a fazer parte de um caminho de ficheiro. Exemplos frequentes são os seletores de idioma que carregam um ficheiro de idioma segundo um parâmetro, a seleção de páginas através de um parâmetro no endereço, a escolha de modelos ou temas e os scripts de download de documentos. Um .php acrescentado no fim do caminho não protege de forma fiável, porque os atacantes podem recorrer a ficheiros PHP existentes.

Obtém uma primeira visão geral com uma pesquisa de inclusões que contenham variáveis. Devolve também resultados inofensivos, mas mostra onde é preciso olhar com mais atenção:

grep -rnE --include='*.php' '(include|require)(_once)?\s*\(?\s*\$' /var/www/projekt \
  | grep -v '/vendor/'

Verifique em cada resultado de onde vem a variável e se um visitante a pode influenciar.

O padrão seguro: lista de permissão em vez de caminho do pedido

A proteção mais fiável é que o visitante escolha apenas uma chave e que a aplicação decida por si qual o ficheiro correspondente. O caminho nunca é composto a partir de entradas.

<?php
declare(strict_types=1);

$seiten = [
    'start'      => __DIR__ . '/../vorlagen/start.php',
    'leistungen' => __DIR__ . '/../vorlagen/leistungen.php',
    'kontakt'    => __DIR__ . '/../vorlagen/kontakt.php',
];

$wahl = is_string($_GET['seite'] ?? null) ? $_GET['seite'] : 'start';

if (!array_key_exists($wahl, $seiten)) {
    http_response_code(404);
    $wahl = 'start';
}

require $seiten[$wahl];

Este padrão é curto, fácil de verificar e não deixa margem. Nas frameworks modernas, o router assume esta tarefa; aí, os controladores e os modelos também nunca devem ser determinados a partir de parâmetros livres.

Quando os nomes de ficheiro têm de ser dinâmicos: realpath e diretório base

Por vezes uma lista fixa não é prática, por exemplo em downloads de uma pasta de documentos. Verifique então o caminho resolvido face a um diretório base fixo e admita apenas nomes de ficheiro simples.

<?php
declare(strict_types=1);

const BASIS = '/var/www/daten/dokumente';

function sichererPfad(string $name): string
{
    if (!preg_match('/^[a-z0-9_-]{1,64}\.pdf$/', $name)) {
        throw new InvalidArgumentException('Ungültiger Dateiname.');
    }

    $basis = realpath(BASIS);
    $pfad  = realpath($basis . DIRECTORY_SEPARATOR . $name);

    if ($basis === false || $pfad === false
        || !str_starts_with($pfad, $basis . DIRECTORY_SEPARATOR)) {
        throw new RuntimeException('Datei nicht gefunden.');
    }

    return $pfad;
}

// Entregar em vez de incluir: o readfile() não executa código.
$datei = sichererPfad((string) ($_GET['datei'] ?? ''));
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($datei) . '"');
readfile($datei);

Dois pontos são decisivos. A expressão regular não admite separadores de diretório nem carateres especiais. E os ficheiros que apenas devem ser entregues são lidos com readfile(), não com include, para que o código neles contido nunca seja executado. O str_starts_with() está disponível a partir do PHP 8.0.

Proteção do lado do servidor: php.ini, open_basedir e permissões

Código seguro é a primeira linha de defesa. A configuração do servidor garante que um erro despercebido cause menos dano.

; php.ini ou pool FPM (php_admin_value / php_admin_flag)
allow_url_include = Off
allow_url_fopen   = Off   ; só se a aplicação não carregar URLs externos
open_basedir      = /var/www/kunde-a/:/tmp/kunde-a/
display_errors    = Off
log_errors        = On

O allow_url_fopen é necessário a algumas aplicações para atualizações ou interfaces. Teste a desativação primeiro num ambiente de teste. O open_basedir limita o PHP às pastas do próprio site, o que é especialmente importante em servidores com vários clientes. Os pormenores estão nos guias open_basedir e isolamento por site e Configurar o php.ini com segurança.

Em complemento, as pastas de uploads e de cache não devem ser executáveis e os ficheiros de registo não devem estar na raiz web. Assim, faltam ao atacante os locais onde poderia colocar conteúdo próprio para uma inclusão.

Como reconhecer tentativas de exploração nos registos

As tentativas de explorar uma file inclusion deixam geralmente vestígios no registo de acessos. Chamam a atenção parâmetros que contêm mudanças de diretório, caminhos absolutos do sistema, stream wrappers ou endereços alheios completos, sobretudo em parâmetros como page, file, template ou lang. Um resultado isolado costuma ser uma varredura automatizada. Importante é saber se tal pedido foi respondido com o código de estado 200 e um tamanho de resposta invulgar.

Como proceder aqui de forma sistemática, descreve-o Analisar os registos do servidor web após um ataque. Se encontrar indícios de acessos bem-sucedidos, parta do princípio de que ficheiros de configuração foram lidos e renove as credenciais neles contidas.

Incluem-se sobretudo as palavras-passe da base de dados, chaves de serviços de pagamento e de envio, acessos SMTP e as chaves secretas do CMS. Verifique ainda se, desde o primeiro acesso suspeito, surgiram ficheiros novos. Quem conseguiu ler ficheiros pode também ter tentado colocar os seus. Neste caso, já não se trata apenas de uma vulnerabilidade no código, mas de um incidente de segurança, que deve ser tratado de forma estruturada.

Garantir as correções de forma duradoura

Após uma correção, vale a pena garantir a função de proteção com testes automatizados. Um teste simples passa à seleção de páginas valores desconhecidos, mudanças de diretório e entradas vazias e espera em todos os casos a página predefinida ou um erro 404. Tais testes evitam que uma alteração posterior volte a abrir a vulnerabilidade sem se notar.

Para a gestão e os responsáveis de projeto, é útil uma pergunta à agência: há na aplicação pontos em que se carregam ficheiros com base em parâmetros e como estão protegidos? Uma resposta concreta, com locais e testes, é um bom sinal.

Como ajuda concretamente a PHP SOS?

  • Procuramos no seu código, de forma orientada, include, require e funções de ficheiros com entradas do pedido e avaliamos cada achado.
  • Definimos allow_url_include, open_basedir e permissões adequadas por site e verificamos que a aplicação continua a funcionar depois.
  • Analisamos os registos quanto a tentativas de exploração e esclarecemos se as credenciais têm de ser renovadas.
  • Para uma verificação independente, oferecemos uma auditoria de segurança com teste de intrusão para aplicações PHP.

Perguntas frequentes

Qual é a diferença entre LFI e RFI?

Na Local File Inclusion, a aplicação carrega um ficheiro que já está no servidor, mas que não devia ser carregado. Na Remote File Inclusion, é carregado código de um endereço alheio. A RFI pressupõe uma definição insegura do PHP, a LFI não.

Basta remover ../ do parâmetro?

Não. Tais filtros podem muitas vezes ser contornados por codificação ou variantes e ignoram caminhos absolutos. Só é seguro um mapeamento fixo de valores permitidos para ficheiros ou uma verificação do caminho resolvido face a um diretório base.

O open_basedir protege totalmente contra a file inclusion?

Não, limita apenas os diretórios a que o PHP pode aceder. Dentro desses limites, a vulnerabilidade continua a poder ser explorada. O open_basedir é uma camada de proteção adicional e não substitui código seguro.

Os CMS como o WordPress são afetados pela LFI?

O núcleo dos CMS comuns é considerado bem verificado neste ponto. As vulnerabilidades surgem antes em extensões, temas e desenvolvimentos próprios. As atualizações das extensões e uma vista de olhos aos seus avisos de segurança são, por isso, importantes.

Fontes

Contacto imediato

Cada hora conta. Escreva-nos agora.

Descreva brevemente o sistema, a versão do PHP e o que observou. Entramos em contacto consigo, esclarecemos a situação e trabalhamos remotamente até o incidente estar concluído e documentado.

Ajuda imediata