Validação e sanitização
Esta aula aborda a validação e sanitização de dados em PHP, explicando como usar filter_var para garantir que entradas do usuário sejam seguras e confiáveis. Cobrimos a validação de tipos específicos (e-mail, URL, inteiros) e a sanitização para remover caracteres perigosos, além de discutir por que nunca devemos confiar em dados enviados pelo cliente.
A validação e sanitização de dados são práticas essenciais para a segurança e integridade de qualquer aplicação web. Em PHP, a função filter_var oferece uma maneira simples e eficaz de verificar e limpar entradas do usuário, prevenindo ataques como injeção de código, XSS e outros. Nesta aula, você aprenderá a usar filter_var com diferentes filtros, entenderá a diferença entre validar e sanitizar, e compreenderá por que nunca devemos confiar em dados provenientes do cliente.
filter_var
A função filter_var é a principal ferramenta do PHP para validação e sanitização de dados. Ela recebe como parâmetros o valor a ser filtrado, o tipo de filtro (constante) e um array opcional de opções. A função retorna o valor filtrado (no caso de sanitização) ou o valor original (se a validação passar), ou false se a validação falhar.
Existem dois tipos principais de filtros: filtros de validação (constantes FILTER_VALIDATE_*) e filtros de sanitização (constantes FILTER_SANITIZE_*). Os filtros de validação verificam se o valor atende a um determinado formato (ex.: e-mail, URL, número inteiro), enquanto os filtros de sanitização removem ou codificam caracteres indesejados.
<?php
// Exemplo básico de filter_var com validação de e-mail
$email = "usuario@exemplo.com";
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo "E-mail válido.";
} else {
echo "E-mail inválido.";
}
// Exemplo de sanitização: remover tags HTML
$texto = "<script>alert('XSS')</script>Olá";
$textoLimpo = filter_var($texto, FILTER_SANITIZE_STRING);
echo $textoLimpo; // Exibe: alert('XSS')Olá (tags removidas)
?>
Note que FILTER_SANITIZE_STRING está obsoleto a partir do PHP 8.1; recomenda-se usar htmlspecialchars() ou strip_tags() para remoção de tags. No entanto, a função ainda funciona em versões mais antigas.
Validando entradas
A validação de entradas consiste em verificar se os dados fornecidos pelo usuário estão no formato esperado. Isso é crucial para evitar dados malformados que possam causar erros ou vulnerabilidades. Os filtros de validação mais comuns incluem:
FILTER_VALIDATE_EMAIL: verifica se o valor é um endereço de e-mail válido (formato básico).FILTER_VALIDATE_URL: verifica se o valor é uma URL válida (com suporte a protocolos).FILTER_VALIDATE_INT: verifica se o valor é um inteiro, com opção de faixa (min_range, max_range).FILTER_VALIDATE_FLOAT: verifica se o valor é um número de ponto flutuante.FILTER_VALIDATE_BOOLEAN: verifica se o valor é um booleano (true, false, 1, 0, "true", "false").FILTER_VALIDATE_IP: verifica se o valor é um endereço IP (IPv4 ou IPv6).FILTER_VALIDATE_MAC: verifica se o valor é um endereço MAC.
Exemplo prático de validação de um campo de idade:
<?php
$idade = $_POST['idade'] ?? '';
$options = array(
'options' => array(
'min_range' => 0,
'max_range' => 150
)
);
if (filter_var($idade, FILTER_VALIDATE_INT, $options) !== false) {
echo "Idade válida: $idade";
} else {
echo "Idade inválida. Deve ser um número entre 0 e 150.";
}
?>
É importante lembrar que a validação deve ser feita tanto no cliente (JavaScript) quanto no servidor (PHP), mas a validação no servidor é a única confiável.
Sanitizando
A sanitização é o processo de limpar os dados, removendo ou codificando caracteres que possam ser perigosos ou indesejados. Diferente da validação, que apenas verifica, a sanitização altera o valor para torná-lo seguro. Os filtros de sanitização mais comuns incluem:
FILTER_SANITIZE_EMAIL: remove caracteres não permitidos em e-mails (exceto letras, dígitos e alguns símbolos).FILTER_SANITIZE_URL: remove caracteres não permitidos em URLs.FILTER_SANITIZE_NUMBER_INT: remove tudo que não é dígito ou sinal de menos.FILTER_SANITIZE_NUMBER_FLOAT: remove tudo que não é dígito, ponto, sinal de menos ou vírgula (opções podem incluir separador decimal).FILTER_SANITIZE_STRING: remove tags HTML e codifica caracteres especiais (obsoleto, usehtmlspecialchars()).FILTER_SANITIZE_ENCODED: codifica a string como URL (percent-encoding).FILTER_SANITIZE_SPECIAL_CHARS: codifica caracteres especiais HTML (equivalente ahtmlspecialchars()).
Exemplo de sanitização de um campo de nome de usuário (permitindo apenas letras e números):
<?php
$username = $_POST['username'] ?? '';
$usernameSanitizado = filter_var($username, FILTER_SANITIZE_STRING); // remove tags
// Para permitir apenas alfanuméricos, use expressão regular:
$usernameFinal = preg_replace('/[^a-zA-Z0-9]/', '', $usernameSanitizado);
echo "Nome de usuário limpo: $usernameFinal";
?>
Outra abordagem comum é usar filter_input ou filter_input_array para filtrar diretamente de superglobais como $_GET, $_POST e $_SERVER.
Por que nunca confiar no cliente
Em aplicações web, todo dado que vem do cliente (navegador) é potencialmente malicioso. O cliente pode ser um usuário mal-intencionado, ou um script automatizado que envia requisições forjadas. Mesmo que o front-end faça validação, ela pode ser facilmente contornada. Portanto, a validação e sanitização no servidor são a última linha de defesa.
Exemplos de riscos ao confiar no cliente:
- Injeção de SQL: Se um campo de texto for usado em uma consulta SQL sem sanitização, um invasor pode inserir comandos SQL maliciosos.
- XSS (Cross-Site Scripting): Se dados não sanitizados forem exibidos em uma página, scripts maliciosos podem ser executados no navegador de outros usuários.
- Injeção de comandos: Se dados forem passados para funções de sistema, comandos arbitrários podem ser executados.
- Manipulação de dados: Um usuário pode alterar campos ocultos, cookies ou cabeçalhos HTTP para burlar regras de negócio.
Para ilustrar, considere um formulário que espera um número inteiro para o campo 'quantidade'. Um invasor pode enviar uma string como "1; DROP TABLE produtos; --" se não houver validação. Com filter_var e validação de inteiro, isso é bloqueado.
<?php
// Simulação de entrada maliciosa
$quantidade = "1; DROP TABLE produtos; --";
if (filter_var($quantidade, FILTER_VALIDATE_INT) !== false) {
// Seguro para usar em consulta (mas ainda use prepared statements)
$quantidade = (int) $quantidade;
} else {
die("Entrada inválida.");
}
?>
Lembre-se: a validação e sanitização são complementares ao uso de prepared statements (para SQL) e escape de saída (para HTML). Sempre combine essas técnicas para uma segurança robusta.
Boas práticas
- Sempre valide e sanitize dados no servidor, mesmo que o cliente já tenha feito.
- Use
filter_inputpara acessar diretamente entradas de formulários e filtrá-las. - Para validação mais complexa, combine
filter_varcom expressões regulares. - Prefira filtros específicos (ex.:
FILTER_VALIDATE_EMAIL) a filtros genéricos. - Não confie apenas na sanitização para segurança; valide o formato antes.
- Mantenha-se atualizado sobre filtros obsoletos (ex.:
FILTER_SANITIZE_STRINGfoi removido no PHP 8.1).
Referências
- PHP Manual: filter_var
- PHP Manual: Lista de filtros
- PHP Manual: Filtros de validação
- PHP Manual: Filtros de sanitização
- PHP Manual: filter_input
- OWASP: Cross-Site Scripting (XSS)
- OWASP: SQL Injection
Exercícios
-
Exercício 1: Escreva um script PHP que receba um e-mail via GET e valide se é um e-mail válido usando
filter_var. Exiba "Válido" ou "Inválido".✓ Resposta:<?php $email = $_GET['email'] ?? ''; if (filter_var($email, FILTER_VALIDATE_EMAIL)) { echo "Válido"; } else { echo "Inválido"; } ?> -
Exercício 2: Usando
filter_varcom opções, valide se um número inteiro recebido via POST está entre 1 e 100. Usemin_rangeemax_range.✓ Resposta:<?php $numero = $_POST['numero'] ?? ''; $options = array('options' => array('min_range' => 1, 'max_range' => 100)); if (filter_var($numero, FILTER_VALIDATE_INT, $options) !== false) { echo "Número válido."; } else { echo "Número inválido."; } ?> -
Exercício 3: Sanitize uma string recebida via POST para remover tags HTML e caracteres especiais (use
FILTER_SANITIZE_STRINGouhtmlspecialchars). Exiba o resultado.✓ Resposta:<?php $texto = $_POST['texto'] ?? ''; // Usando htmlspecialchars (recomendado para exibição) $textoLimpo = htmlspecialchars($texto, ENT_QUOTES, 'UTF-8'); echo $textoLimpo; // Alternativa com filter_var (obsoleto) // $textoLimpo = filter_var($texto, FILTER_SANITIZE_STRING); ?> -
Exercício 4: Crie uma função que receba uma URL e retorne a URL sanitizada (removendo caracteres inválidos) e validada. Se for inválida, retorne false.
✓ Resposta:<?php function validarESanitizarURL($url) { // Sanitiza primeiro $urlSanitizada = filter_var($url, FILTER_SANITIZE_URL); // Valida if (filter_var($urlSanitizada, FILTER_VALIDATE_URL)) { return $urlSanitizada; } return false; } $url = "http://exemplo.com/teste<script>"; $resultado = validarESanitizarURL($url); if ($resultado) { echo "URL válida e sanitizada: $resultado"; } else { echo "URL inválida."; } ?> -
Exercício 5: Explique com suas palavras por que é importante validar e sanitizar dados no servidor, mesmo que o front-end já tenha feito a validação. Dê um exemplo de ataque que poderia ser evitado.
✓ Resposta:A validação no servidor é essencial porque o cliente pode ser manipulado. Um invasor pode desabilitar JavaScript, usar ferramentas como curl ou Postman para enviar requisições diretamente, ou interceptar e modificar dados em trânsito. A validação no front-end é apenas para melhorar a experiência do usuário, não para segurança. Por exemplo, um campo de e-mail pode ser validado no front-end, mas um invasor pode enviar uma requisição POST com um payload malicioso como "<script>alert('XSS')</script>" no campo de e-mail. Se o servidor não sanitizar ou validar, esse script pode ser executado no navegador de outros usuários (XSS). A validação e sanitização no servidor impedem que dados maliciosos sejam processados ou armazenados.