Resolver problemas

auto_prepend_file e auto_append_file

Revisto a 7 min de leitura depuração PHP

auto_prepend_file configura um ficheiro que o PHP carrega através de uma operação equivalente a require antes do ficheiro principal. auto_append_file faz o mesmo depois do ficheiro principal, exceto quando a execução termina através de exit(). Ambas as diretivas utilizam include_path.

Não são equivalentes aos include, require nem ao autoload do Composer: aplicam-se a partir da configuração do PHP e podem afetar todas as execuções abrangidas por essa configuração.

Por exemplo, a firewall do Wordfence pode utilizar auto_prepend_file para filtrar pedidos antes de carregar o WordPress. Verifique o seu valor atual antes de o alterar: substituí-lo por um script de diagnóstico pode deixar essa proteção por executar.

Perante uma nova infeção, comece pela fonte de diagnóstico mais restrita: a hora e o caminho indicados pelo histórico de segurança, as marcas temporais e diferenças do ficheiro afetado e os registos de acesso e de segurança dentro desse intervalo.

Um pedido POST próximo no tempo é apenas um candidato: não demonstra que esse pedido tenha modificado o ficheiro nem identifica que plugin processou o pedido. No WordPress, vários componentes podem receber pedidos através de index.php, admin-ajax.php ou da API REST.

Só se essas fontes não permitirem seguir a execução é que auto_prepend_file pode ser utilizado temporariamente para registar metadados concretos de pedidos futuros. Nunca registe o corpo POST completo.

Passo a passo

Crie previamente /home/CPANEL_USUARIO/private com permissões 0700. Depois crie, fora de public_html, o ficheiro /home/CPANEL_USUARIO/private/request-debug.php com o conteúdo seguinte, ajustando action, plugin e event aos únicos campos necessários para a investigação:

<?php

(function (): void {

$logFile = '/home/CPANEL_USUARIO/private/request-debug.log';

if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
    return;
}

clearstatcache(true, $logFile);
$logSize = is_file($logFile) ? filesize($logFile) : 0;

if (is_int($logSize) && $logSize >= 5 * 1024 * 1024) {
    return;
}

$selectedFields = [];

foreach (['action', 'plugin', 'event'] as $field) {
    if (isset($_POST[$field]) && is_scalar($_POST[$field])) {
        $selectedFields[$field] = substr((string) $_POST[$field], 0, 200);
    }
}

$entry = [
    'time' => date(DATE_ATOM),
    'method' => $_SERVER['REQUEST_METHOD'],
    'path' => parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH),
    'fields' => $selectedFields,
];

$encoded = json_encode(
    $entry,
    JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE
);

if (is_string($encoded)) {
    $previousMask = umask(0077);
    try {
        if (file_put_contents($logFile, $encoded.PHP_EOL, FILE_APPEND | LOCK_EX) !== false) {
            chmod($logFile, 0600);
        }
    } finally {
        umask($previousMask);
    }
}
})();

Substitua CPANEL_USUARIO pelo seu utilizador do cPanel.

Este script guarda apenas o caminho, o método e os campos selecionados, e verifica um limiar de 5 MiB antes de escrever. Não é um limite estrito: pedidos simultâneos ou a última entrada podem ultrapassá-lo. Reveja o tamanho durante a janela de diagnóstico. Não acrescente campos de palavra-passe, autorização, cookies, tokens, dados pessoais ou de pagamento; se um valor legítimo puder conter informação sensível, oculte-o ou substitua-o por um hash antes de o registar. O script e o registo devem pertencer ao utilizador do cPanel, e o registo deve manter as permissões 0600.

Este registo apenas fornece metadados para correlacionar um pedido candidato. Não demonstra que esse pedido tenha causado a modificação e não é uma evidência resistente a manipulações: um atacante com acesso de escrita à mesma conta poderia alterá-lo ou desativá-lo.

Depois disto, no ficheiro .htaccess de public_html, acrescente logo no início:

php_value auto_prepend_file '/home/CPANEL_USUARIO/private/request-debug.php'

Mais uma vez, substitua o utilizador do cPanel pelo correspondente. A diretiva afetará as execuções PHP abrangidas por esse .htaccess, normalmente também nos seus subdiretórios. Valide primeiro o script com a mesma versão de PHP que o site usa.

Se, ao acrescentar php_value, surgir um erro 500, retire imediatamente a linha e consulte o registo de erros. Só uma mensagem que identifique a diretiva como inválida ou não permitida confirma que o controlador não admite configurá-la a partir do .htaccess.

Defina antes de começar uma janela de captura curta e um tamanho máximo. Ao terminar, elimine imediatamente a linha auto_prepend_file, apague request-debug.php e destrua o registo quando as evidências deixarem de ser necessárias. Enquanto o conservar, limite o acesso ao pessoal que realiza a análise e aplique uma retenção explícita; não o guarde indefinidamente.

Esta captura não substitui a resposta ao incidente. Mesmo que permita relacionar um pedido com uma modificação, ainda é preciso confirmar que código o processou, fechar a via de entrada, rever mecanismos de persistência, reinstalar componentes a partir de fontes fiáveis, mudar as credenciais afetadas e verificar que não ficam outros ficheiros ou utilizadores alterados.

Conserve o valor anterior de auto_prepend_file e restaure-o ao terminar. Se for gerido por uma firewall, não o substitua sem preparar uma integração compatível numa cópia de testes. Verifique também que o próprio caminho e os campos selecionados não contêm identificadores pessoais; omita qualquer dado de que não precise. O exemplo restaura a máscara de permissões depois de escrever, para não alterar a forma como a aplicação cria os seus próprios ficheiros.

Também lhe pode ser útil

Algo não bate certo ou mudou? Diga-nos e revemos.