Situazione attuale: PHP2Shell. Due vulnerabilità critiche di PHP (CVSS 9,2) consentono codice dannoso senza autenticazione. Patch dal 21/10/2026.Che cosa fare ora →

Validare e filtrare gli input in PHP con filter_var

Come gli sviluppatori verificano gli input in PHP con filter_var, filter_input_array e liste di valori consentiti, quali filtri sono obsoleti e perché la validazione non sostituisce prepared statement e codifica dell'output.

Stato 6 min di letturaSviluppo sicuro

In breve: gli input in PHP si validano con filter_var() o filter_input_array() e con regole chiare per ogni campo: tipo, intervallo, lunghezza e valori consentiti. Ciò che non corrisponde viene rifiutato, non rimaneggiato in silenzio. La validazione è importante per dati puliti e meno superficie di attacco, ma non sostituisce né i prepared statement contro la SQL injection né la codifica adeguata al contesto contro l'XSS.

Perché «filtrare tutto» non è un concetto

In molti progetti PHP più vecchi, all'inizio di ogni file si trova un ciclo che fa passare tutti i valori di $_GET e $_POST attraverso una funzione di pulizia. Dà una sensazione di sicurezza. Nella pratica a volte rimuove troppo, ad esempio gli apostrofi nei cognomi, e a volte troppo poco, perché la stessa funzione dovrebbe valere contemporaneamente per SQL, HTML e nomi di file.

Una validazione sensata funziona diversamente: per ogni campo si chiede che cosa vi sia consentito. Una quantità ordinata è un numero intero tra 1 e un limite superiore. Un campo di ordinamento è uno di tre valori fissi. Una data ha un formato determinato e viene dopo un'altra data. Tutto il resto viene rifiutato.

OWASP distingue due livelli: la verifica sintattica, cioè se un valore ha la forma giusta, e la verifica semantica, cioè se nel contesto ha senso. Entrambe appartengono al server; le verifiche nel browser servono solo all'usabilità.

Quali filtri offre PHP

L'estensione dei filtri è inclusa in PHP per impostazione predefinita. I principali filtri di validazione secondo il manuale PHP:

Filtro Verifica Opzioni e note importanti
FILTER_VALIDATE_INT Numero intero min_range, max_range
FILTER_VALIDATE_FLOAT Numero decimale decimal per il separatore
FILTER_VALIDATE_BOOL Valore di verità Con FILTER_NULL_ON_FAILURE distinguibile da «falso»
FILTER_VALIDATE_EMAIL Forma di un indirizzo e-mail Non dimostra che la casella esista
FILTER_VALIDATE_URL Forma di un URL Controllare lo schema da sé, nessun dominio internazionalizzato
FILTER_VALIDATE_IP Indirizzo IP Flag per intervalli privati e riservati
FILTER_VALIDATE_REGEXP Schema proprio Ancorare lo schema con ^ e $

Il filtro di pulizia FILTER_SANITIZE_STRING è obsoleto da PHP 8.1. Chi lo usa ancora dovrebbe passare per la validazione a filtri adatti e usare htmlspecialchars() per l'output.

filter_var in PHP: verificare bene un modulo

Con filter_input_array() si può verificare un intero modulo in un solo passaggio rispetto a una definizione. I campi sconosciuti non vengono acquisiti:

<?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);
    // Mostrare un messaggio di errore per campo, non elaborare gli input
}

Faccia attenzione ai confronti rigorosi con ===: un valore valido 0 o una stringa vuota non vanno scambiati con un fallimento. Perché qui i confronti laschi siano pericolosi lo spiega Type juggling: i confronti laschi come rischio di sicurezza. Come PHP metta a disposizione i dati della richiesta lo descrive Superglobali: $_GET, $_POST, $_FILES e simili.

Insidie con e-mail, URL e testi liberi

Alcuni filtri fanno meno di quanto il nome lasci supporre:

  1. URL: FILTER_VALIDATE_URL accetta anche schemi diversi da http e https. Controlli poi lo schema con parse_url() rispetto a un elenco fisso. Se l'URL viene richiamato dal server, valgono regole aggiuntive, vedi Prevenire il Server-Side Request Forgery in PHP.
  2. Indirizzi e-mail: il filtro verifica la forma, non il possesso. Chi deve esserne certo invia un link di conferma.
  3. Testo libero: nomi, messaggi e indirizzi difficilmente si possono limitare in modo sensato a certi caratteri. Verifichi lunghezza e codifica dei caratteri, ad esempio con mb_check_encoding($wert, 'UTF-8'), e in fase di output si affidi alla codifica.
  4. Espressioni regolari: senza ^ e $ uno schema verifica solo se compare da qualche parte nel testo, non se corrisponde l'intero valore.
  5. Array al posto di stringhe: un aggressore può inviare un array invece di un testo. Senza verifica del tipo ciò porta ad avvisi o a comportamenti imprevisti.
Consiglio

Per valori di scelta fissi come ordinamento, lingua o modalità di spedizione, una lista consentita con in_array($wert, $erlaubt, true) o un'espressione match è più semplice e più rigorosa di qualsiasi espressione regolare.

Un altro errore frequente riguarda i numeri con un significato, come prezzi, quantità o sconti. Il fatto che un valore sia un numero valido non dice nulla sul fatto che nel contesto sia consentito. Una quantità negativa, uno sconto superiore al valore della merce o un prezzo ripreso dal modulo anziché dal database sono classici errori logici. Prezzi, autorizzazioni e valori di stato appartengono perciò sempre al server e mai a campi nascosti del modulo.

JSON, webhook e importazioni: validazione oltre i moduli

Oggi molti ingressi non sono più moduli, ma richieste JSON da app, webhook di servizi di pagamento o file di importazione dei fornitori. Anche lì vale: prima leggere in sicurezza, poi verificare. OWASP consiglia di limitare dimensione e profondità di annidamento prima ancora di leggere i dati. In PHP json_decode() con una profondità massima e JSON_THROW_ON_ERROR se ne occupa in parte:

<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // al massimo 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;
}

Per i webhook, prima della verifica del contenuto c'è la domanda se il messaggio provenga davvero dal servizio indicato. Se il servizio offre una firma, la verifichi e la confronti con hash_equals(). Per i file di importazione verifichi ogni riga come un modulo e interrompa in modo pulito in caso di errori, anziché acquisire record a metà.

I messaggi di errore dovrebbero nominare il campo interessato, ma non restituire senza filtro il valore rifiutato. Altrimenti nel messaggio di errore stesso nasce un nuovo punto di output, che va a sua volta codificato.

Che cosa la validazione non può fare

La validazione riduce la superficie di attacco, ma secondo OWASP non è la difesa principale contro l'injection. Un cognome con apostrofo è valido e deve comunque arrivare in sicurezza in un database. Ciò riesce solo con i prepared statement, come mostra la guida Prevenire la SQL injection in PHP. E un testo di commento valido diventa innocuo solo con una codifica adeguata al contesto in fase di output.

L'ordine giusto è dunque: validare alla ricezione, parametrizzare nell'elaborazione, codificare nell'output. In più, prima di tutto ciò vanno posti limiti di dimensione: richieste decisamente troppo grandi non dovrebbero nemmeno essere elaborate per intero da server web e PHP. A questo servono impostazioni come post_max_size, che dopo PHP2Shell andrebbero comunque verificate.

Come aiuta concretamente PHP SOS?

  • Rileviamo tutti gli ingressi della sua applicazione: moduli, interfacce, upload, importazioni e webhook.
  • Stabiliamo per ogni campo che cosa è consentito e sostituiamo le funzioni di pulizia generiche con verifiche chiare.
  • Verifichiamo se accessi al database e output sono messi in sicurezza indipendentemente dalla validazione.
  • Documentiamo le regole in modo che il suo team possa proseguirle con le nuove funzioni.

Una verifica sistematica è descritta nel servizio audit di sicurezza e penetration test.

Domande frequenti

Qual è la differenza tra validare e ripulire?

Validare verifica se un valore corrisponde alle aspettative e, in caso contrario, lo rifiuta. Ripulire modifica il valore, ad esempio rimuovendo caratteri. Per le decisioni di sicurezza rifiutare è quasi sempre meglio, perché un valore modificato in silenzio può generare nuovi errori.

FILTER_SANITIZE_STRING è ancora utilizzabile?

Il filtro è contrassegnato come obsoleto da PHP 8.1. Il manuale PHP raccomanda invece htmlspecialchars() in fase di output. Il codice esistente andrebbe aggiornato, perché le funzioni obsolete possono essere eliminate nelle versioni future.

FILTER_VALIDATE_URL basta per rendere sicuri i link?

No. Il filtro verifica solo la forma dell'indirizzo. Secondo il manuale un URL valido non deve necessariamente iniziare con http, quindi lo schema va controllato da sé rispetto a una lista consentita come https. Il filtro rifiuta i nomi di dominio internazionalizzati.

Devo validare anche i dati del mio database?

In fase di output sono considerati non affidabili e vengono codificati in modo adatto. Una nuova validazione ha senso se i dati provenivano originariamente dall'esterno e ora vengono usati in un nuovo contesto, ad esempio come nome di file o parte di un comando.

La validazione aiuta contro PHP2Shell?

No. PHP2Shell riguarda l'elaborazione delle richieste nell'interprete PHP, prima ancora che giri il codice della sua applicazione. Contro di esso aiuta solo l'aggiornamento di PHP con il successivo riavvio di tutti i processi PHP.

Fonti

Contatto immediato

Ogni ora conta. Ci scriva adesso.

Descriva brevemente sistema, versione di PHP e quanto osservato. Ci faremo sentire, chiariremo la situazione e lavoreremo da remoto fino alla chiusura e alla documentazione dell'incidente.

Aiuto immediato