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 →

Validar e filtrar entradas em PHP com filter_var

Como os programadores verificam entradas em PHP com filter_var, filter_input_array e listas de permissão, que filtros estão obsoletos e porque é que a validação não substitui prepared statements nem a codificação da saída.

Atualizado em 6 min de leituraDesenvolvimento seguro

Em resumo: As entradas em PHP validam-se com filter_var() ou filter_input_array() e regras claras por campo: tipo, intervalo, comprimento e valores permitidos. O que não corresponde é rejeitado, não transformado em silêncio. A validação é importante para dados limpos e menos superfície de ataque, mas não substitui nem os prepared statements contra a injeção de SQL nem a codificação adequada ao contexto contra o XSS.

Porque é que “filtrar tudo” não é um conceito

Em muitos projetos PHP mais antigos, encontra-se no início de cada ficheiro um ciclo que passa todos os valores de $_GET e $_POST por uma função de limpeza. Parece seguro. Na prática, ora remove demasiado, por exemplo apóstrofos em apelidos, ora demasiado pouco, porque a mesma função deveria valer ao mesmo tempo para SQL, HTML e nomes de ficheiro.

A validação com sentido funciona de outra forma: pergunta, para cada campo, o que aí é permitido. Uma quantidade encomendada é um número inteiro entre 1 e um limite superior. Um campo de ordenação é um de três valores fixos. Uma data tem um determinado formato e é posterior a outra data. Tudo o resto é rejeitado.

A OWASP distingue dois níveis: a verificação sintática, que vê se um valor tem a forma certa, e a verificação semântica, que vê se faz sentido no contexto. Ambas pertencem ao servidor; as verificações no navegador servem apenas a usabilidade.

Que filtros o PHP traz

A extensão Filter vem incluída por defeito no PHP. Os principais filtros de validação segundo o manual do PHP:

Filtro Verifica Opções importantes e notas
FILTER_VALIDATE_INT número inteiro min_range, max_range
FILTER_VALIDATE_FLOAT número decimal decimal para o separador
FILTER_VALIDATE_BOOL valor lógico com FILTER_NULL_ON_FAILURE distingue-se de “falso”
FILTER_VALIDATE_EMAIL forma de um endereço de e-mail não prova que a caixa de correio exista
FILTER_VALIDATE_URL forma de um URL verificar o esquema por si, sem domínios internacionalizados
FILTER_VALIDATE_IP endereço IP flags para intervalos privados e reservados
FILTER_VALIDATE_REGEXP padrão próprio ancorar o padrão com ^ e $

O filtro de saneamento FILTER_SANITIZE_STRING está obsoleto desde o PHP 8.1. Quem ainda o usa deve migrar a validação para filtros adequados e usar htmlspecialchars() na saída.

filter_var em PHP: verificar um formulário de forma limpa

Com filter_input_array() pode verificar-se um formulário inteiro de uma só vez contra uma definição. Os campos desconhecidos não são aceites:

<?php
declare(strict_types=1);

$regeln = [
    'menge'   => ['filter' => FILTER_VALIDATE_INT,
                  'options' => ['min_range' => 1, 'max_range' => 50]],
    'email'   => FILTER_VALIDATE_EMAIL,
    'agb'     => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
    'versand' => ['filter' => FILTER_VALIDATE_REGEXP,
                  'options' => ['regexp' => '/^(standard|express)$/']],
];

$daten  = filter_input_array(INPUT_POST, $regeln) ?? [];
$fehler = [];

foreach ($regeln as $feld => $_) {
    if (!array_key_exists($feld, $daten) || $daten[$feld] === false || $daten[$feld] === null) {
        $fehler[] = $feld;
    }
}

if ($fehler !== []) {
    http_response_code(422);
    // mostrar a mensagem de erro por campo, não processar as entradas
}

Repare nas comparações estritas com ===: um valor válido 0 ou uma string vazia não pode ser confundido com uma falha. Porque é que as comparações laxas são aqui perigosas é explicado em Type juggling: comparações laxas como risco de segurança. Como o PHP disponibiliza, afinal, os dados do pedido é descrito em Superglobals: $_GET, $_POST, $_FILES e companhia.

Armadilhas com e-mail, URL e textos livres

Alguns filtros fazem menos do que o nome sugere:

  1. URLs: o FILTER_VALIDATE_URL aceita também outros esquemas além de http e https. Verifique depois o esquema com parse_url() contra uma lista fixa. Se o URL for consultado pelo servidor, aplicam-se regras adicionais, ver Evitar Server-Side Request Forgery em PHP.
  2. Endereços de e-mail: o filtro verifica a forma, não a posse. Quem precisa de certeza envia um link de confirmação.
  3. Texto livre: nomes, mensagens e moradas dificilmente se deixam restringir a carateres de forma útil. Verifique o comprimento e a codificação de carateres, por exemplo com mb_check_encoding($wert, 'UTF-8'), e confie na codificação na saída.
  4. Expressões regulares: sem ^ e $, um padrão verifica apenas se ocorre em algum ponto do texto, não se o valor inteiro corresponde.
  5. Arrays em vez de strings: um atacante pode enviar um array em vez de um texto. Sem verificação de tipo, isso leva a avisos ou a comportamento inesperado.
Dica

Para valores de seleção fixos, como ordenação, idioma ou forma de envio, uma lista de permissão com in_array($wert, $erlaubt, true) ou uma expressão match é mais simples e mais estrita do que qualquer expressão regular.

Outro erro frequente diz respeito a números com significado, como preços, quantidades ou descontos. Que um valor seja um número válido nada diz sobre se é permitido no contexto. Uma quantidade negativa, um desconto superior ao valor da mercadoria ou um preço retirado do formulário em vez da base de dados são erros de lógica clássicos. Preços, permissões e valores de estado pertencem por isso sempre ao servidor e nunca a campos ocultos de formulário.

JSON, webhooks e importações: validação para além dos formulários

Muitas entradas já não são formulários, mas pedidos JSON de aplicações, webhooks de serviços de pagamento ou ficheiros de importação de fornecedores. Também aí vale: primeiro ler com segurança, depois verificar. A OWASP aconselha a limitar o tamanho e a profundidade de aninhamento antes de os dados serem sequer lidos. Em PHP, o json_decode() com uma profundidade máxima e JSON_THROW_ON_ERROR assume parte disso:

<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // no máximo 64 KB
try {
    $daten = json_decode($roh, true, 16, JSON_THROW_ON_ERROR);
} catch (JsonException) {
    http_response_code(400);
    exit;
}
if (!is_array($daten) || !is_string($daten['bestellnummer'] ?? null)) {
    http_response_code(422);
    exit;
}

Nos webhooks, antes da verificação do conteúdo está a pergunta se a mensagem vem realmente do serviço indicado. Se o serviço oferecer uma assinatura, verifique-a e compare-a com hash_equals(). Nos ficheiros de importação, verifique cada linha como um formulário e interrompa de forma limpa em caso de erro, em vez de aceitar registos incompletos.

As mensagens de erro devem indicar o campo em causa, mas não devolver sem filtro o valor rejeitado. Caso contrário, surge na própria mensagem de erro um novo ponto de saída, que tem de voltar a ser codificado.

O que a validação não consegue fazer

A validação reduz a superfície de ataque, mas, segundo a OWASP, não é a defesa principal contra a injeção. Um apelido com apóstrofo é válido e tem, mesmo assim, de chegar em segurança a uma base de dados. Isso só se consegue com prepared statements, como mostra o guia Evitar SQL Injection em PHP. E um texto de comentário válido só se torna inofensivo com a codificação adequada ao contexto na saída.

A ordem certa é, portanto: validar na receção, parametrizar no processamento, codificar na saída. Além disso, os limites de tamanho vêm antes: pedidos demasiado grandes nem sequer devem ser processados por completo pelo servidor web e pelo PHP. Para isso servem definições como post_max_size, que após o PHP2Shell devem de qualquer modo ser revistas.

Como ajuda concretamente a PHP SOS?

  • Registamos todas as entradas da sua aplicação: formulários, interfaces, uploads, importações e webhooks.
  • Definimos por campo o que é permitido e substituímos funções de limpeza genéricas por verificações claras.
  • Verificamos se os acessos à base de dados e as saídas estão protegidos independentemente da validação.
  • Documentamos as regras de modo a que a sua equipa as possa continuar em novas funções.

Uma verificação sistemática é descrita no serviço Auditoria de segurança e teste de intrusão.

Perguntas frequentes

Qual é a diferença entre validar e sanear?

Validar verifica se um valor corresponde ao esperado e, caso contrário, rejeita-o. Sanear altera o valor, por exemplo removendo carateres. Para decisões de segurança, rejeitar é quase sempre melhor, porque um valor alterado em silêncio pode gerar novos erros.

O FILTER_SANITIZE_STRING ainda pode ser usado?

O filtro está marcado como obsoleto desde o PHP 8.1. O manual do PHP recomenda, em vez disso, htmlspecialchars() na saída. Deve migrar o código existente, porque as funções obsoletas podem desaparecer em versões futuras.

O FILTER_VALIDATE_URL chega para tornar os links seguros?

Não. O filtro verifica apenas a forma do endereço. Segundo o manual, um URL válido não tem de começar por http, por isso tem de verificar o esquema você mesmo contra uma lista de permissão como https. Os nomes de domínio internacionalizados são rejeitados pelo filtro.

Tenho de validar também os dados da minha própria base de dados?

Na saída são considerados não fiáveis e codificados de forma adequada. Uma nova validação faz sentido quando os dados vieram originalmente do exterior e passam agora a ser usados num novo contexto, por exemplo como nome de ficheiro ou parte de um comando.

A validação ajuda contra o PHP2Shell?

Não. O PHP2Shell afeta o processamento de pedidos no interpretador PHP, antes de o código da sua aplicação sequer correr. Contra isso só ajuda a atualização do PHP seguida do reinício de todos os processos PHP.

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