PHP: filtrare l'input dei form per prevenire gli attacchi XSS

PHP: filtrare l'input dei form per prevenire gli attacchi XSS

Gli attacchi di tipo XSS (Cross-Site Scripting) sono una delle pratiche più diffuse (e fastidiose) di inserimento di contenuti malevoli su pagine web dinamiche. In passato questo tipo di attacchi poteva avere conseguenze disastrose per l'utente in alcuni browser (IE 5.5 su Windows 98 aveva un bug che permetteva la scrittura nel registro di sistema direttamente tramite VBScript). Con l'andare del tempo e l'evoluzione dell'euristica degli antivirus, le conseguenze di questo tipo di attacchi sono state in un certo senso limitate ma non hanno mai perso la loro pericolosità. Per prevenire questo tipo di attacchi in PHP occorre convincersi che ogni tipo di input da parte dell'utente è potenzialmente pericoloso (gli esperti americani parlano di tainted data) e usare il maggior numero di filtri possibile prima di lavorare effettivamente sui dati passati da un form. La funzione che presento in questo articolo non è la soluzione definitiva al problema XSS, ma solo un altro filtro che possiamo aggiungere agli altri già esistenti.

La funzione è la seguente:


function sanitizeXSS($data)
{
// Entità
$data = str_replace(array('&','<','>'), array('&','<','>'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

// Via gli attributi che iniziano con on o xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

// Via i protocolli javascript: e vbscript:
$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

// Via le expression() di IE
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

// Via gli elementi con namespace
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);

do {
        // Tag indesiderati (si può ampliare l'elenco)
        $old_data = $data;
        $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
}
while ($old_data !== $data);

return $data;
}

Questa funzione filtra le entità SGML, rimuove gli attributi degli eventi inline JavaScript, elimina i protocolli di scripting dagli URL e le espressioni dinamiche di Internet Explorer. Infine, filtra i tag indesiderati.

Torna su