MySQL e SQL Injection
Se prendi l'input dell'utente attraverso una pagina web e lo inserisci in un database MySQL, c'è la possibilità che ti sei lasciato aperto per un problema di sicurezza noto come SQL Injection. Questo capitolo ti insegnerà come evitare che ciò accada e ti aiuterà a proteggere i tuoi script e le istruzioni MySQL.
L'SQL Injection di solito si verifica quando chiedi un input a un utente, come il suo nome e invece di un nome ti danno un'istruzione MySQL che eseguirai inconsapevolmente sul tuo database.
Non fidarti mai dei dati forniti da un utente, elabora questi dati solo dopo la convalida; di regola, questo viene fatto dalla corrispondenza del modello. Nell'esempio seguente, il nome utente è limitato a caratteri alfanumerici più trattino basso e una lunghezza compresa tra 8 e 20 caratteri: modificare queste regole secondo necessità.
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
$result = mysql_query("SELECT * FROM users WHERE username = $matches[0]");
} else {
echo "username not accepted";
}
Per dimostrare questo problema, considera il seguente estratto.
// supposed input
$name = "Qadir'; DELETE FROM users;";
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
La chiamata alla funzione dovrebbe recuperare un record dalla tabella degli utenti, dove la colonna del nome corrisponde al nome specificato dall'utente. In circostanze normali, $ name conterrebbe solo caratteri alfanumerici e forse spazi. Ma qui, aggiungendo una query completamente nuova a$name, la chiamata al database si trasforma in un disastro. La query DELETE inserita rimuove tutti i record dagli utenti.
Fortunatamente, se usi MySQL, il file mysql_query()funzione non consente lo stacking di query o l'esecuzione di più query in una singola chiamata di funzione. Se si tenta di impilare le query, la chiamata non riesce.
Tuttavia, altre estensioni di database PHP, come SQLite e PostgreSQL, esegue felicemente query impilate, eseguendo tutte le query fornite in una stringa e creando un serio problema di sicurezza.
Prevenire SQL injection
Puoi gestire tutti i caratteri di escape in modo intelligente nei linguaggi di scripting come PERL e PHP. L'estensione MySQL per PHP fornisce la funzionemysql_real_escape_string() per sfuggire ai caratteri di input che sono speciali per MySQL.
if (get_magic_quotes_gpc()) {
$name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
Il dilemma LIKE
Per risolvere il dilemma LIKE, un meccanismo di escape personalizzato deve convertire i caratteri% e _ forniti dall'utente in letterali. Usoaddcslashes(), una funzione che consente di specificare un intervallo di caratteri di cui eseguire l'escape.
$sub = addcslashes(mysql_real_escape_string("%something_"), "%_");
// $sub == \%something\_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");