SQL Injection

Se prendi l'input di un utente tramite una pagina Web e lo inserisci in un database SQL, è possibile che ti sia lasciato aperto 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 SQL negli script lato server come uno script PERL.

L'iniezione di solito si verifica quando chiedi un input a un utente, come il suo nome e invece di un nome ti danno un'istruzione SQL che eseguirai inconsapevolmente sul tuo database. Non fidarsi mai dei dati forniti dall'utente, elaborare questi dati solo dopo la convalida; di regola, questo viene fatto daPattern Matching.

Nell'esempio seguente, il file name è limitato ai caratteri alfanumerici più il trattino basso e ad 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 CUSTOMERS 
      WHERE name = $matches[0]");
} else {
   echo "user name not accepted";
}

Per dimostrare il problema, considera questo estratto:

// supposed input
$name = "Qadir'; DELETE FROM CUSTOMERS;";
mysql_query("SELECT * FROM CUSTOMSRS WHERE name='{$name}'");

La chiamata di funzione dovrebbe recuperare un record dalla tabella CUSTOMERS in cui la colonna del nome corrisponde al nome specificato dall'utente. In circostanze normali,$nameconterrebbe solo caratteri alfanumerici e forse spazi, come la stringa ilia. 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 dalla tabella CUSTOMERS.

Fortunatamente, se usi MySQL, il file mysql_query()la funzione non consente lo stacking delle query o l'esecuzione di più query SQL 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 eseguire tranquillamente query in pila, 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 CUSTOMERS 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("%str"), "%_");
// $sub == \%str\_
mysql_query("SELECT * FROM messages 
   WHERE subject LIKE '{$sub}%'");