flawopen.com/Inclusão de arquivos/PHP include()
O include() do PHP é seguro com dados do usuário?
Não. include() interpreta o arquivo selecionado como PHP, mas o impacto depende do arquivo alcançado e de seu conteúdo. Uma falha pode expor código-fonte por um wrapper, incluir um arquivo local inesperado ou executar PHP controlado pelo atacante apenas quando ele consegue influenciar conteúdo com tags PHP e a aplicação o inclui. A inclusão por URL remota também depende da configuração do PHP. Associe uma chave escolhida pelo usuário a uma lista fixa; nunca monte o caminho de include a partir da requisição.
<?php // User-controlled path: unintended local file include $_GET['page'] . '.php'; // Example selector: ../../private/sample // Impact depends on the resolved file and // whether it contains PHP code to interpret. // Remote URL inclusion requires the relevant // URL wrapper and allow_url_include setting. // Wrappers can change which resource is read; // php://filter is a read filter, not a path // containment check.
<?php // Allowlist: input selects a KEY, // never a path or wrapper. $pages = [ 'home' => __DIR__ . '/pages/home.php', 'about' => __DIR__ . '/pages/about.php', 'contact' => __DIR__ . '/pages/contact.php', ]; $key = $_GET['page'] ?? 'home'; if (!is_string($key) || !array_key_exists($key, $pages)) { http_response_code(404); exit; } include $pages[$key];
Por que a inclusão local não significa execução de código automaticamente
A inclusão local não executa código automaticamente. O PHP interpreta o arquivo incluído; instruções dentro de tags PHP válidas são executadas no contexto que inclui o arquivo, enquanto outros bytes podem ser enviados como saída. A execução exige um arquivo acessível com PHP controlado pelo atacante ou outro comportamento explorável. Por exemplo, uma falha de upload ou gravação de logs pode formar uma cadeia se colocar conteúdo PHP controlado em um arquivo que depois seja incluído.
Separadamente, php://filter aplica um filtro ao abrir um fluxo. Em um fluxo vulnerável de leitura ou inclusão, um filtro adequado pode expor texto-fonte sem executá-lo; a leitura depende do wrapper, das permissões e da configuração da aplicação.
Por que sanitizar o caminho não resolve
Remover ../, acrescentar uma extensão fixa ou prefixar um diretório não prova que o recurso final é aprovado. Codificações, caminhos absolutos, regras da plataforma e wrappers podem mudar a interpretação. Remova o controle do usuário sobre o recurso: permita selecionar apenas chaves de uma lista fixa definida pela aplicação.
Se precisar resolver um caminho, canonicalize com realpath() e verifique que ele está dentro do diretório, como descrito no guia de Path Traversal. Restrinja o resultado a arquivos aprovados e considere symlinks e condições de corrida entre checagem e uso. Uma allowlist de destinos fixos é mais segura.
Perguntas frequentes
Essa opção desativa wrappers de URL em include/require. O PHP a documenta como desativada por padrão e obsoleta desde PHP 7.4. Isso reduz a exposição a inclusão remota, mas não impede traversal local nem includes locais inseguros. Mantenha-a desativada e remova o controle do usuário sobre o destino.
O PHP 5.3.4 corrigiu a terminação por byte nulo no tratamento de caminhos. Não use a ausência dessa técnica antiga como defesa: destinos de include não confiáveis continuam inseguros.
require e as variantes _once também incluem e interpretam o destino; diferem no tratamento de falhas e inclusões repetidas, mas não tornam seguro um destino não confiável. readfile() e file_get_contents() retornam dados sem interpretá-los como PHP; caminhos não confiáveis podem causar traversal ou exposição, não execução pelo include.
Referências
- Manual do PHP — include
- Manual do PHP — protocolos e wrappers
- Manual do PHP — configuração de inclusão por URL
- Manual do PHP — wrapper php://filter
- OWASP — teste de inclusão local de arquivos
- CWE-98 — controle de nomes para include/require
- A verificação lexical de path.join() basta para impedir traversal?