Quando si tratta di query di database, provare sempre a utilizzare query parametrizzate preparate. Le librerie mysqli
e lo PDO
supportano. Questo è infinitamente più sicuro rispetto all'utilizzo di funzioni di escape come mysql_real_escape_string
.
Sì, mysql_real_escape_string
è effettivamente solo una funzione di escape della stringa. Non è una bacchetta magica. Tutto ciò che farà è sfuggire a caratteri pericolosi in modo che possano essere usati in sicurezza in una singola stringa di query. Tuttavia, se non disinfetti in anticipo i tuoi input, sarai vulnerabile a determinati vettori di attacco.
Immagina il seguente SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Dovresti essere in grado di vedere che questo è vulnerabile agli exploit.
Immagina che il id
parametro contenga il vettore di attacco comune:
1 OR 1=1
Non ci sono caratteri rischiosi da codificare, quindi passerà direttamente attraverso il filtro di fuga. Lasciandoci:
SELECT fields FROM table WHERE id= 1 OR 1=1
Che è un adorabile vettore di SQL injection e consentirebbe all'autore dell'attacco di restituire tutte le righe. O
1 or is_admin=1 order by id limit 1
che produce
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
Ciò consente all'autore dell'attacco di restituire i dettagli del primo amministratore in questo esempio completamente fittizio.
Sebbene queste funzioni siano utili, devono essere utilizzate con cautela. È necessario assicurarsi che tutti gli input Web siano convalidati in una certa misura. In questo caso, vediamo che possiamo essere sfruttati perché non abbiamo verificato che una variabile che stavamo utilizzando come numero fosse effettivamente numerica. In PHP dovresti usare ampiamente un insieme di funzioni per verificare che gli input siano numeri interi, float, alfanumerici ecc. Ma quando si tratta di SQL, fai attenzione al valore dell'istruzione preparata. Il codice precedente sarebbe stato sicuro se fosse stata un'istruzione preparata poiché le funzioni del database avrebbero saputo che 1 OR 1=1
non è un valore letterale valido.
Quanto a htmlspecialchars()
. Questo è un campo minato a sé stante.
C'è un vero problema in PHP in quanto ha un'intera selezione di diverse funzioni di escape relative a HTML e nessuna guida chiara su esattamente quali funzioni fanno cosa.
In primo luogo, se ti trovi all'interno di un tag HTML, sei davvero nei guai. Guarda a
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Siamo già all'interno di un tag HTML, quindi non abbiamo bisogno di <o> per fare nulla di pericoloso. Il nostro vettore di attacco potrebbe esserejavascript:alert(document.cookie)
Ora appare l'HTML risultante
<img src= "javascript:alert(document.cookie)" />
L'attacco arriva dritto.
Peggiora. Perché? perché htmlspecialchars
(se chiamato in questo modo) codifica solo virgolette doppie e non singole. Quindi se lo avessimo fatto
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Il nostro malvagio aggressore ora può iniettare parametri completamente nuovi
pic.png' onclick='location.href=xxx' onmouseover='...
ci da
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
In questi casi, non c'è nessuna bacchetta magica, devi solo santizzare l'input da solo. Se provi a filtrare i personaggi cattivi, fallirai sicuramente. Adotta un approccio da whitelist e lascia passare solo i caratteri che sono buoni. Guarda il cheat sheet XSS per esempi su come possono essere diversi i vettori
Anche se utilizzi htmlspecialchars($string)
al di fuori dei tag HTML, sei comunque vulnerabile ai vettori di attacco con set di caratteri multibyte.
Il più efficace che puoi essere è usare una combinazione di mb_convert_encoding e htmlentities come segue.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Anche questo lascia IE6 vulnerabile, a causa del modo in cui gestisce UTF. Tuttavia, potresti ricorrere a una codifica più limitata, come ISO-8859-1, fino a quando l'utilizzo di IE6 non diminuisce.
Per uno studio più approfondito sui problemi multibyte, vedere https://stackoverflow.com/a/12118602/1820