Hai un sito web realizzato con PHP e MySQL e hai paura che possa cadere vittima di SQL Injection? Vuoi delle tecniche semplici da applicare al tuo sito per proteggerlo da eventuali attacchi di SQL Injection?
Quando si parla di sicurezza e protezione dei dati personali, non bisogna trascurare nessun aspetto, neanche il più piccolo e insignificante. Questa considerazione ha ancora più valore se parliamo di siti web, dove ogni errore di programmazione potrebbe essere sfruttato per attacchi di hacking e diventare una vera e propria porta di accesso all’interno del sistema informatico.
Al giorno d’oggi la stragrande maggioranza dei siti web online sono realizzati in PHP, uno dei linguaggi di programmazione più conosciuto ed utilizzato, da cui in genere estrae dati e informazioni da un database SQL.
Questa “accoppiata” permette agli sviluppatori di realizzare siti web dinamici, in maniera semplice e affidabile. Con poche istruzioni è possibile realizzare piattaforme complesse e all’avanguardia, estraendo, salvando, modificando ed eliminando dati dal database in tutta facilità .
Purtroppo però, quando si sviluppa con PHP e MySQL, bisogna stare attenti a molti aspetti e mettere in sicurezza il tutto attraverso delle specifiche tecniche per evitare l’SQL Injection, la più grande piaga di ogni sito web.
In questo articolo cercherò di spiegare anche ai principianti ed a chi non è del settore, in maniera semplice e dettagliata, come mettere in sicurezza in proprio sito in modo da evitare l’SQL Injection, descrivendo come avviene un attacco di questo genere e come viene sfruttato da eventuali hacker e spammer.
Tutto su SQL Injection e le tecniche per difendersi
Un sito mal sviluppato potrebbe rivelarsi una facile preda di SQL Injection. Se hai paura di diventare la sua prossima vittima, qui ti darò degli utili consigli e rivelerò le migliori tecniche da poter adottare per proteggere te, i tuoi iscritti e il tuo sito.
Ognuno di questi metodi è facilmente replicabile per ogni sito web, puoi adattarle alle tue esigenze in modo da difenderti da eventuali attacchi al database.
Prima di iniziare però, per chi non ha ben chiaro di cosa stiamo parlando, spiegherò brevemente cosa è e come avviene una SQL injection e perché è tanto temuta.
Potrebbe interessanti anche: Come difendersi da attacchi di brute force.
Cos’è una SQL Injection?
Una SQL injection è uno sfruttamento di vulnerabilità generata comunemente dagli elementi di input presenti in una pagina internet con cui possono interagire gli utenti esterni.
I dati contenuti nei form (moduli) e nei campi di input HTML (come quelli dell’email, password o testo), dopo essere stati compilati ed inviati al server dall’utente, vengono elaborati dal database su cui poggia il sito.
I moduli, se non vengono opportunamente protetti tramite apposite funzioni PHP e altre tecniche (che mostreremo più avanti), possono essere appunto sfruttati tramite l’inserimento di caratteri speciali e apposite keywords SQL.
In questo modo è possibile accedere, leggere o eliminare dati, e tabelle contenuti nel database. L’impatto di un eventuale attacco SQL può avere forti ripercussioni negative, portare al furto dei dati personali degli utenti come ad esempio password, email o dati di pagamento, e molte altre conseguenze.
Come viene eseguita
L’esempio più noto di SQL injection è il seguente:
Ipotizziamo una comune query SQL, una richiesta di accesso di un login, per accedere ad un sito web.
$user= $_POST['user'];
$password= $_POST['password'];
$sql = "SELECT * FROM tab_users WHERE user='".$user."' AND password='".$password."'";
$result = mysql_query($conn_db, $sql);
Le prime due variabili PHP prelevano i dati da elementi di input HTML di un form, chiamati “user” e “password“.
A questo punto dopo l’invio dei dati al server tramite il modulo, questo restituirà un responso positivo o negativo in base al fatto che i dati siano corretti oppure no. Fin qui nulla di strano.
Prendendo ora in esempio il codice precedente, l’injection ora può avvenire in questo modo:
Per chi ha un minimo di conoscenza di SQL, sa bene quali siano le keyword o istruzioni utilizzate per la compilazione di una query per il database.
Un eventuale hacker può cercare di manomettere il database utilizzando l’input della password, digitando semplicemente password' OR 1='1
. Il sistema in questo caso eseguirà questa query:
"SELECT * FROM tab_users WHERE user='' AND password='password' OR 1='1'";
La query in questione indica che può l’utente può accedere se 1 è uguale a 1 o password è uguale a password. La condizione è sempre vera e dunque verrà eseguito l’accesso al sistema anche senza credenziali reali.
Con un sistema privo di difese simile a quello dell’esempio, un hacker può accedere direttamente nel sistema e manipolare a proprio piacimento tutte le informazioni del database.
Ci sono altre pratiche per scoprire se un sistema informatico di questo genere sia poco sicuro, ma fondamentalmente sono molto simili tra loro e sfruttano le stesse eventuali debolezze del sito.
Gli sviluppatori hanno molte tecniche a disposizione per proteggere il database da SQL Injection, e qui cercherò di descriverne alcuni dei migliori.
Come proteggersi
Online è possibile trovare differenti tecniche per difendere un sito da SQL injections, tutte più o meno efficaci, alcune incomplete o di vecchia data.
In base alla mia esperienza, ho deciso di elencare alcune delle migliori e testate, poco invasive e facili da applicare anche per utenti meno esperti.
In caso di dubbi non esitare a contattarmi ed a scrivere un commento.
Evita errori di programmazione
Ok, questa non è una vera tecnica, ma è un consiglio importante.
Scrivere correttamente il proprio codice, soprattutto per query MySQL è fondamentale per evitare tentativi di attacco hacker.
Query incomplete o programmate male possono far generare errori, accompagnati da messaggi specifici con riferimenti sulla struttura del database. Se questi errori dovessero comparire agli utenti sbagliati, potrebbero sfruttarli per SQL injection e accedere al sistema.
Ad esempio, quando una tabella o una colonna non esiste, magari perché scritta erroneamente, possono comparire messaggi di questo genere:
Errore Table 'localhost.tabella-utenti' doesn't exist
Oppure:
Errore Unknown column 'nomeutente' in 'field list'
A prima vista potrebbero sembrare messaggi con poco significato, ma in realtà sono informazioni preziose per hacker e il primo passo verso una SQL injection.
Stando a quanto detto finora, potresti anche pensare di adottare un metodo di soppressione dei messaggi generati da MySQL. L’idea di fondo potrebbe essere buona, ma è molto sconsigliato farlo.
Le tecniche per nascondere errori del database possono portare ad altri problemi e incompatibilità , oltre che alla soppressione anche di avvisi utili per migliorie ed ottimizzazioni. Molti utenti hanno riscontrato problemi funzionali dovuti a tale disabilitazione.
Dunque potresti tentare, ma dovrai tenere sotto controllo costante tutte le funzioni del sito per assicurarti che tutto vada come dovrebbe.
La miglior cosa da fare resta comunque una buona scrittura delle query, test approfonditi e un uso della corretta sintassi SQL.
Da “MySQL” a “MySQLi”
Con le versioni più recenti di MySQL e PHP, è cambiata anche al sintassi da utilizzare per un elaborazione più sicura delle query.
In passato per l’invio di una query SQL al server si faceva uso delle funzioni “mysql_
“. Questo modello è ora deprecato per far spazio a versioni e funzioni più ottimizzate e sicure.
Le alternative utilizzabili sono MySQLi (“i” per “improved“, cioè migliorato) oppure PDO (PHP data objects, consigliato per l’uso con altri database oltre a MySQL). Per farla semplice, se il tuo sito ad oggi fa ancora uso dello standard MySQL deprecato, puoi aggiornarlo facilmente aggiungendo la lettera “i” sulle funzioni. Ad esempio “mysql_query
” diventa “mysqli_query
“.
Se il tuo sito è di recente concezione o fa uso di un CMS aggiornato, non dovresti temere questo passaggio in quanto dovrebbe già utilizzare le funzioni più recenti.
PHP mysqli_real_escape_string()
La funzione PHP mysqli_real_escape_string() è una delle più utilizzate per difendere un sito da SQL injection. Sviluppata ad-hoc per questo scopo, la funzione mysqli_real_escape_string() consiste in una pre-elaborazione dei dati inviati tramite un modulo web, convertendo i caratteri speciali ostili alla query e rendendo innocui i tentativi di hacking.
Ai caratteri speciali come l’apice (‘) ad esempio, verrà aggiunto il simbolo \ per la conversione in formato testuale.
Puoi usare la funzione mysqli_real_escape_string() per elaborale le richieste PHP $_POST degli elementi di input HTML, in questo modo:
$user = mysqli_real_escape_string($conn_db, $_POST['username'];
$pass = mysqli_real_escape_string($conn_db, $_POST['password'];
<form method="post" action="login.php">
<input type="text" name="username">
<input type="password" name="password">
</form>
Un modulo programmato in questo modo verrà protetto da comuni tentativi di SQL injection, simili a quello visto in precedenza.
Questo metodo è uno dei preferiti dagli sviluppatori per difendere il proprio sito e database; dovresti adottarlo ogni qual volta c’è un invio di informazioni tramite un modulo/form.
La variabile $conn_db
è quella che stabilisce la connessione con il database del sito, in cui sono registrati i dati di accesso a quest’ultimo. In genere questa variabile è creata all’interno di un file specifico (chiamato ad esempio config.php o conn.php).
SQL prepared statement
Per SQL Prepared Statement si indica la preparazione anticipata delle query SQL prima dell’invio al server per l’inserimento di valori nel database. Con una normale query avviene una connessione diretta al server, che poi elaborerà le informazioni eseguendo l’azione richiesta dall’utente.
Con il sistema “prepared” si aggiunge un ulteriore passaggio all’operazione, ovvero la preparazione della query.
Con questa istruzione lo sviluppatore può decidere il tipo di informazioni che dovranno essere inviati in base a dei parametri prestabiliti, la query effettiva verrà eseguita successivamente se tutti i requisiti sono rispettati. Tutto questo risulta molto utile contro l’SQL injection.
Con una funzione SQL prepared si hanno però anche altri vantaggi, come una memorizzazione della query per l’invio multiplo (evita l’invio di più richieste al server, rendendole più veloci).
Per dichiarare una query SQL prepared puoi fare uso del metodo PDO o MySQLi. Ecco alcuni esempi:
$sql = $conn->prepare("INSERT INTO tabella (nome, cognome, email) VALUES (?, ?, ?)");
$sql->bind_param("sss", $nome, $cognome, $email);
Spiegazione del codice:
- Nella prima riga avviene la preparazione della query con la funzione
prepare()
; - I valori da inserire nel database sono mascherati dal simbolo “?“, che verranno sostituiti successivamente;
- Nella seconda riga vengono definite le tipologie dei valori da inviare. “sss” sta per “stringa+stringa+stringa“;
- Se le variabili
$nome
,$cognome
e$email
risultano stringhe di testo, la condizione viene soddisfatta e la query inviata.
Nell’esempio abbiamo visto “sss” come valore stringa, ce ne sono altri da imparare:
- i – Numero intero;
- d – Numero reale (,);
- s – Stringa;
- b – Blob.
Ti rimando al sito w3schools.com per altri esempi.
Blocco dei caratteri speciali negli URL con .htaccess
Un’altra tecnica sicura per difendersi da injections SQL è il blocco dei caratteri speciali negli URL del sito. In realtà non è un vero e proprio blocco dei caratteri, ma il risultato finale è molto simile.
Lo scopo di questa tecnica è, attraverso un’istruzione nel file .htaccess del sito, impedire che gli URL contenenti i caratteri ostili (come: ‘,”, drop, delete) non vengano eseguiti e gli utenti vengano reindirizzati verso un’altra pagina del sito, come la home page.
Questo perché una SQL injection può essere effettuata anche con l’invio di dati attraverso l’URL di una pagina, questo perché in un sito web possono essere presenti molte funzioni che si attivano attraverso il reindirizzamento di link, che contengono parametri per le query SQL.
Per questa prativa consiglio di bloccare le keywords e simboli speciali “pericolosi” utilizzando direttamente il file .htaccess, inserendo il codice in basso:
#parole vietate
RewriteEngine On
RewriteCond %{QUERY_STRING} (%27|\'|drop|delete) [NC]
RewriteRule ^(.*)$ http://miosito.it/? [R=302,L]
Come puoi vedere, ogni volta che si tenta di digitare caratteri come ‘apice‘ (anche nel suo formato testuale %27) o le parole DROP e DELETE per l’eliminazione di voci con SQL, il sito reindirizzerà automaticamente alla home page.
Il punto di forza di questa istruzione è che non può essere aggirata in alcun modo. L’unico svantaggio è che alcuni siti web potrebbero fare uso di questi caratteri negli URL, magari per una funzione di ricerca interna o altre funzioni. Perciò valuta attentamente se puoi farne uso per il tuo sito e personalizza il codice in htaccess aggiungendo o rimuovendo le “parole vietate” che desideri.
Blocco dei caratteri speciali nelle aree di input
I “punti deboli” di un sito che invia e riceve informazioni ad un database sono le aree con cui gli utenti interagiscono. Le aree di input testuali presenti su una pagina web, per la compilazione di un modulo (come ad esempio quelli per l’accesso, registrazione o contatto) sono gli elementi sfruttati da eventuali hacker per l’SQL injection.
I webmasters, per evitare che questi elementi HTML di input possano essere sfruttati contro il sito stesso, hanno a disposizione diversi strumenti, come il blocco dei caratteri speciali (come quelli che abbiamo visto nel paragrafo precedente).
Quando si realizza un form HTML, ogni campo presente ha uno scopo ben preciso. I più utilizzati sono questi:
- Input di testo, per testi brevi, piccole descrizioni o l’inserimento di username;
- Password, per l’inserimento di password;
- Email, per la digitazione di indirizzi email;
- Area di testo estesa (textarea);
Per ognuno di questi, è facile capire quali valori dovranno essere immessi, per cui come sviluppatori possiamo porre delle limitazioni e dei blocchi per aumentare la sicurezza del sito.
Per imporre questi blocchi abbiamo più tecniche:
Se sei un principiante, puoi affidarti all’attributo pattern HTML e le espressioni regolari:
<!-- campo password, impedisce l'uso del simbolo 'apice' -->
<input type="password" required pattern="[^':]*$" >
<!-- campo di testo, blocca l'uso dei simboli speciali e spazi -->
<input type="text" pattern="^[a-zA-Z][a-zA-Z0-9-_\.]$">
N.B. Gli input HTML di tipo email sono programmati con un pattern speciale predefinito, non si consiglia di modificarlo.
Tuttavia l’uso dei pattern è bypassabile facilmente. Un altro metodo è con PHP e la convalida delle stringe. In questo caso non si può superare il blocco imposto dallo sviluppatore poiché avviene una convalida dei valori da parte del server. Il principio è lo stesso che con i pattern HTML, ma non può essere aggirato in egual modo.
Un esempio:
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["username"])) {
echo "Campo vuoto, digita un nome";
}
// Controlla che il campo contenga solo lettere e spazi bianchi
if (!preg_match("/^[a-zA-Z ]*$/",$username)) {
echo "Sono consentite solo lettere e spazi bianchi";
}
}
Si consiglia sempre di abbinare questa tecnica con la funzione PHP mysqli_real_escape_string();
Scopri altri metodi di “PHP form validation” sul sito w3schools.com.
Conclusioni
Queste sono alcune delle migliori tecniche per proteggersi da SQL injections. Sono tutte testate e funzionanti, ma come ho spiegato nei vari paragrafi, alcune di esse potrebbero non essere adatte a tutti i siti web.
Nel caso tu stessi utilizzando un CMS moderno e aggiornato, come WordPress ad esempio, non dovresti tenere conto di questo aspetto, in quanto il software è già ampiamente ottimizzato contro questo tipo di attacco.
La guida è pensata specialmente per chi è alle prime armi con lo sviluppo di siti web complessi che gestiscono dati e informazioni personali di persone e iscritti.
Fai molti testi prima di pubblicare online piattaforme appoggiate su dei database SQL, anche una piccola svista o un errore d programmazione possono portare a seri problemi, difficili da risolvere per chi ha poca esperienza.
Se hai bisogno di consigli particolari, ricorda che puoi sempre contattarci e scriverci un commento. Saremo ben lieti di aiutarti.
Leggi anche: Come velocizzare un sito web
Iscriviti alla nostra Newsletter qui e seguici su Facebook per aggiornamenti!
Articoli recenti:
- Recensione In Fuga. Ciclo Le Cronache dell’Ultimo Druido di Kevin Hearne
- Recensione Fool Moon di Jim Butcher
- Recensione Storm Front di Jim Butcher
- Upgrade Scheda Rete. Sostituzione della Realtek RTL8822CE
- Da jQuery a JavaScript Puro: Sfruttare il Potenziale Nativo del Web