SQL Injection

Introduzione e considerazioni sulla tattica di web hacking più popolare al mondo

Glossario

1. Introduzione

1.1 Disclaimer

1.2 Cos’è la SQL Injection?

1.3 Rilevanza nel 2018

2. Let’s hack

2.1 Union SQL Injection

2.2 Error Based SQL Injection

2.3 Automatizzare la roba noiosa con sqlmap

2.4 WAF

3. Come difendersi

3.1 Prerequisiti

3.2 Escape e Binding

4. Riferimenti

1. Introduzione

1.1 Disclaimer

Prima di cominciare, direi di aprire una parentesi su quello che per gli inglesi è un DISCLAIMER, cosicchè tu non perda tempo leggendo cose di cui non hai bisogno.

Questo può essere considerato come un documento informativo di base inerente (come da titolo) a una tecnica di web hacking detta SQL Injection, non sarà molto diversa da quelle che trovi online, tuttavia raccoglie un insieme di studi che probabilmente fanno in modo che la lettura di questo documento sembri più un “diario” sulle mie considerazioni, piuttosto che una vera e propria guida.

Qualora questo documento presentasse delle inesattezze, ti prego di scusarmi e di considerare tali inesattezze come sbagli in un lungo percorso di apprendimento.

Non è necessaria alcuna competenza particolare per seguire questa lettura, tuttavia una conoscenza di base del linguaggio SQL (di cui saranno comunque interpretati i fondamentali nel corso dei nostri esperimenti) può agevolare notevolmente la lettura del documento.

Specifico infine che tutti i test sono stati effettuati su sistemi volutamente vulnerabili e costruiti appositamente per essere attaccati, scopo della guida è quello di condividere le mie considerazioni su quanto studiato, non mi propongo né mi auguro di fare del lettore un criminale, motivo per il quale delego ogni responsabilità al buon senso di chi mi legge.

1.2 Cos’è la SQL Injection?

La SQL Injection è una tattica di web hacking il cui scopo è quello di sfruttare insicurezze nel sistema di un sito web per iniettare codice malevolo al fine di spulciare informazioni a un database SQL.

Delle insicurezze parleremo dopo, adesso concentriamoci su due parole: Database e SQL.

Un database, in parole molto povere, è un contenitore di dati all’interno di un sito web; pensa ad esempio alle chat di Facebook… ogni volta che chiudi e riapri la finestra del tuo browser e rientri nel tuo account Facebook, le conversazioni che hai fatto ieri le troverai anche oggi, questo succede perché Facebook conserva i dati delle tue chat per permetterti di rivederle quando ti riconnetti al tuo account.

In particolare un database è composto da tabelle che a loro volta contengono colonne, righe e celle (se sei familiare con Excel, avrai già intuito di cosa sto parlando), per evitare di dilungarci troppo ti lascio un immagine autoesplicativa che ti permetterà di capire al volo la struttura di una tabella di tipo generico:

… ora immagina solo di moltiplicare questa tabella per 10, 100, 1000, ecco, hai ottenuto un database, questa tabella gestisce i dati dell’utente di un ipotetico social network, ci sarà poi la tabella che gestisce le chat, quella che gestisce i “mi piace” e così via.

SQL è un linguaggio di query, ai non esperti posso dire di considerare SQL come il linguaggio con cui si parla alla stragrande maggioranza dei database; nel nostro esempio della chat di Facebook, il linguaggio SQL è utilizzato per ordinare al database di conservare i tuoi dati in apposite tabelle che saranno probabilmente collegate al tuo account attraverso meccanismi che a noi poco interessano, ciò che è importante capire è che il database ha bisogno di istruzioni, SQL è la risposta a questo problema.

Ma cosa succederebbe se io potessi sfruttare questo potente linguaggio per dare istruzioni a un database che non è mio? Potrei leggere dati riservati, eliminare le celle e le tabelle, modificare le informazioni e tanto altro ancora… questo è quello che la SQL Injection si occupa di fare.

1.3 Rilevanza nel 2018

Qualcuno, tra i più esperti di voi, potrebbe pensare che ad oggi attacchi di SQL Injection sono da considerarsi roba passata ed in parte, ahimè… hanno ragione. Oggi, gran parte dei grandi siti web e CMS (come WordPress) hanno protezioni contro attacchi di questo tipo (dopo ne parleremo un po’ più nel dettaglio) che garantirebbero una maggiore protezione. In aggiunta a ciò, molti siti web fanno uso di firewall per impedire attacchi come la SQL Injection, purtroppo questo metodo sembra essere piuttosto scadente e nel corso di questa lettura imparerai anche a bypassare un firewall.

Appurato ciò, il problema non è del tutto estinto; la SQL Injection è tutt’ora nella top 10 di OWASP (2017) sulle vulnerabilità più comuni di un sito web e, sebbene con qualche ostacolo in più, può ancora rivelarsi essere uno strumento vincente per accedere alle informazioni riservate di un sito web.

2. Let’s hack

Abbiamo abbondantemente discusso di SQL Injection, ora sai cos’è, dove trovarla e hai un’idea delle sue potenzialità… è tempo di sporcarci le mani e cominciare a sperimentare noi stessi quanto discusso precedentemente.

Prima di cominciare un altro piccolo DISCLAIMER: come già specificato, tutti i test sono stati effettuati su sistemi volutamente vulnerabili costruiti appositamente per testare attacchi di questo tipo, in particolare, mi avvalgo di BWAPP come macchina vittima. Non spiegherò i dettagli dell’installazione onde evitare di dilungarmi troppo, delego quindi al lettore l’arduo compito di installare BWAPP sulla propria macchina.

In questo documento saranno trattate due tecniche di SQL Injection (tra l’altro le più comuni): Union SQL Injection e Error Based SQL Injection, vedremo infine come automatizzare il tutto con sqlmap.

2.1 Union SQL Injection

La Union SQL Injection è la tattica più utilizzata di SQL Injection.

Il principio dietro a questa tecnica di web hacking è quello di concatenare le informazioni. Nello specifico, andremo a concatenare le informazioni che il programmatore del sito web ha chiesto per gestire il suo database, con le informazioni che vogliamo ottenere noi, utilizzando SQL.

Il tutto avverrà nella barra URL del tuo browser!

La prima cosa da fare sarà quindi cercare un URL vulnerabile da attaccare, in genere si fa riferimento ad alcune liste dork per trovare facilmente una preda da attaccare, tuttavia scopo di questo documento non è quello di renderti un criminale, quindi mi limiterò ad analizzare la struttura generica di un URL vulnerabile, sarai poi tu, con i termini e le conoscenze acquisite, a riconoscere potenziali link difettosi.

Un URL difettoso ad attacchi di SQL Injection può presentarsi in questa forma:

… in cui:

  • https:// è il protocollo del sito web,
  • www.tuosito.it/ è il dominio
  • galleria?id=1 è una richiesta al database

Quello che intendo con richiesta al database è che l’URL fa riferimento a una query SQL che caricherà una galleria di immagini in cui l’attributo ID, utilizzato in SQL per rendere univoco un dato, ha come valore 1.

Qui entra in gioco la SQL Injection, se il mio input non è filtrato (ovvero, se non vengono fatti controlli su quanto scrivo nella barra URL) posso arricchire quella semplice richiesta al database con qualcosa di un po’ più interessante ed ottenere i dati che mi servono per penetrare nel sistema.

Senza ulteriori indugi, vediamo subito un esempio concreto e cerchiamo di ottenere lo username e la password di un sito web vulnerabile, nel mio caso, bwapp.

L’URL si presenta così:

… probabilmente avrai notato che non c’è nessun “https://” o “www.qualcosa.it”, non preoccuparti… questo è assolutamente normale dal momento in cui sto facendo esperimenti con la mia macchina e non a un sito web reale.

Escluso protocollo e dominio, la richiesta URL è molto simile a quella precedentemente analizzata, la prova che ci garantisce al 99.9% che il sito web è vulnerabile è data dall’aggiunta di un semplice apice (‘) alla fine dell’URL, se otteniamo un’errore allora probabilmente il sito web è vulnerabile ad attachi di SQL Injection:

… da cui ottengo:

… direi che possiamo cominciare a interrogare il database.

In primis, proviamo a chiedere al database quante tabelle contiene, non vogliamo (possiamo) ancora sapere quali esse siano. Per far ciò, andremo a tentativi, ovvero andrò a raggruppare le tabelle utilizzando il comando SQL GROUP BY.

Ipotizziamo che io stia ipotizzando il database composto da 129 tabelle, andrò a scrivere nella barra URL una cosa del genere:

… i trattini alla fine sono semplici commenti, servono ad ordinare al database di ignorare tutto ciò che verrà dopo le mie istruzioni (incluse le istruzioni che il programmatore del sito web aveva preparato), da questa query ottengo:

… questo vuol dire che la tabella contiene meno di 129 tabelle.

Procedendo a tentativi arrivo alla soluzione, ovvero al punto in cui non ho più quest’errore:

… continuo a ricevere errori, questo vuol dire che le mie tabelle saranno meno di 10 e continuando in questo modo arrivo a capire che le mie tabelle sono 7, infatti se provassi a chiederne 8 otterrei un errore, che non ho se chiedo solamente 7 tabelle:

… adesso, dove prima c’era un’errore, ora c’è semplicemente una serie di dati relativamente inutili ai nostri scopi.

Ora che sappiamo quante tabelle abbiamo, vogliamo sapere quali… ovvero vogliamo sapere i nomi delle tabelle e scegliere quella da cui vogliamo ricavare informazioni (come la tabella utenti, per fare un esempio).

Per far ciò, mi avvalgo di un nuovo comando SQL: UNION SELECT; il cui compito è semplicemente quello di unire la query che il sito web usa per fornirci il servizio, con una quella che inserisco io per ottenere i nomi delle tabelle. La query risultante assomiglierà a questa:

Cosa importante, anche se non sempre necessaria, sarà quella di invalidare la richiesta, possiamo farlo semplicemente andando a inserire un uguaglianza matematica falsa (Eg. 1=0, 3=8…) all’interno della barra URL, qualcosa del genere:

… con and 1=0 stiamo invalidando la richiesta, questo ci permetterà di inserire i nostri comandi SQL:

… nessuna differenza particolare, al posto di GROUP BY adesso c’è UNION SELECT seguito da una serie di numeri che corrispondono e devono corrispondere al numero di tabelle precedentemente identificato. Diamo un’occhiata alla pagina web, adesso:

… esattamente ciò che speravo di ottenere. Questi numeri corrispondono alle tabelle che possiamo usare per ottenere informazioni.

Per quanto suoni confuso il concetto è molto semplice, al posto di UNION SELECT 1,2,3,4,5,6,7 andremo a scrivere, per esempio: UNION SELECT 1, nome_tabelle, versione_database, 4,5,6,7… come puoi notare le tabelle disponibili sono 2,3,4,5, questo significa che posso utilizzare queste tabelle per visualizzare le informazioni che m’interessano, tuttavia nulla mi vieta di utilizzare solo due di queste tabelle, in questo caso al posto di 2, 3 ho inserito nome_tabelle e versione_database… mentre ho lasciato intatte le altre tabelle.

Questo, in SQL, si traduce con:

… l’unica variabile è “from information_schema.tables, per ora ti basta sapere che tutti i nomi delle nostre tabelle e delle nostre colonne sono conservati in un database speciale chiamato information_schema, quindi se vogliamo ottenere informazioni sulle tabelle di un database, dobbiamo prenderle da information_schema.tables, se invece ci interessano le colonne utilizziamo analogamente information_schema.columns. Vediamo cosa ci restituisce la pagina web:

… mh, sinceramente questo non è quello che mi aspettavo. Il mio scopo era di ottenere una tabella che potesse essermi utile, la tabella CHARACTER_SETS non mi serve a molto.

Pare che questo sito restituisca un risultato alla volta, nonostante ci siano modi per aggirare il problema e velocizzare notevolmente il processo, per non interrompere il ritmo della spiegazione e soprattutto perché a noi interessa il concetto e non l’efficienza, lascio al lettore l’eventuale compito di approfondire la questione.

Qui mi avvalgo di un terzo comando: LIMIT che banalmente mi permette di scalare una tabella dopo l’altra (una alla volta) fino ad arrivare a quella che m’interessa. Arricchisco la mia query:

LIMIT 0,1 mi dice di prendere la prima tabella, ovvero la nostra CHARACTER_SETS

LIMIT 1,1 mi dirà quindi di prendere la seconda tabella

LIMIT 2,1 mi dirà quindi di prendere la terza tabella

… procedo in questo modo e dopo tanti LIMIT arrivo alla tabella che m’interessa, users.

Ci stiamo avvicinando al nostro scopo, vogliamo ora sapere quante e quali colonne sono contenute nella tabella users. La query è praticamente uguale a quella precedente, con l’unica sostanziale differenza che passiamo da tables a columns.

… da cui ottengo:

… mh, non è quello che mi aspettavo, vero? Il problema è molto semplice, non ho specificato che le colonne che mi interessano devono essere prelevate dalla tabella users; risolviamo subito:

… da cui ottengo:

… ovvero una vera e propria colonna della tabella users.

Non mi resta che giocare con LIMIT ancora una volta per ottenere uno alla volta le informazioni che m’interessano:

… corrisponde alla prima colonna, id… andiamo avanti:

… corrisponde alla seconda colonna, login… questa colonna potrebbe interessarmi, tuttavia continuo la ricerca:

… corrisponde alla terza colonna, password.

Direi di poter fermare la mia ricerca, abbiamo ottenuto due colonne login e password all’interno della tabella users, adesso non mi resta che analizzarne i valori e sperare contengano informazioni utili.

Ottenere i valori è relativamente semplice, tutto ciò che dobbiamo fare è costruire una query che dica al database di prelevare i valori contenuti nelle colonne login e password dalla tabella users, ricordandoci che le colonne disponibili sono la 2,3,4,5… vado a sfruttare le colonne 2, 3 (nulla mi vieterebbe di sfruttare la 2, 4 o la 3, 5 o la 3, 4 e così via):

… come vedi al posto di 2 e 3 ho inserito il nome delle due colonne che abbiamo trovato in precedenza e invece di information_schema.tables ho inserito il nome della tabella da cui pescare le colonne; questa query mi restituisce:

… nella colonna “Title” possiamo notare uno username, nella colonna “Release” una password oscurata tramite meccanismi di crittografia.

L’ultima cosa che ci resta da fare sarà quindi ottenere la password nella sua versione leggibile, nulla di più semplice, ci sono migliaia di siti che si occupano di fare tutto il lavoro per noi, io sono solito utilizzare HashKiller, tieni bene a mente che in contesti reali le cose potrebbero essere più macchinose di così, gli algoritmi di crittografia sono sempre più sofisticati e non sempre sarà facile uscirne vincitori:

… la password sarà quindi bug,

Proviamo ad accedere al sito con i dati appena ottenuti:

In questa prima parte siamo quindi riusciti a penetrare in un sistema sfruttando la tattica di web hacking più comune al mondo, successivamente proveremo ad utilizzare una tecnica di SQL Injection lievemente diversa ma altrettanto potente.

2.2 Error Based SQL Injection

Vediamo ora un’altra tecnica di SQL Injection molto simile a quella analizzata precedentemente.

Questo tipo di tecnica può ritornarci utile nel momento in cui vogliamo ottenere le informazioni da un database ma per qualche ragione non siamo in grado di vedere i risultati delle nostre query SQL.

La Error Based SQL Injection sfrutta, come suggerisce il nome, gli errori che SQL genera automaticamente, permettendoci di ottenere indirettamente le informazioni che cerchiamo.

In particolare ci avvaleremo di un nuovo semplicissimo comando: extractvalue().

Come vedremo a breve, questa tecnica risulta essere molto simile a quella vista in precedenza se escludiamo il fatto che qui non andiamo più a concatenare le query con union select, ma sfruttiamo gli errori con extractvalue().

Una query generica si presenta così:

… di cui extractvalue(0x0a, concat(0x0a, ( ))) è la parte fissa in cui inserire le tue query all’interno delle parentesi, come ad esempio:

  • extractvalue(0x0a, concat(0x0a, ( database() ))) per ottenere il nome del database

Nota bene che nei casi in cui sfruttiamo la Error Based SQL Injection non sarà necessario invalidare l’input.

Proviamo quindi ad inserire quest’ultima query nella barra URL e vediamo cosa ne esce fuori:

… da cui ottengo:

… ovvero il nome del database.

Come puoi notare quindi, stiamo sfruttando degli errori di sintassi per ottenere le informazioni che cerchiamo; proviamo a spingerci oltre e cerchiamo di capire da quali tabelle è composto questo database, la query si presenta così:

… fin qui nulla di nuovo, vero? La query contenuta tra le parentesi è pressappoco simile a quella usata precedentemente, con l’unica differenza che qui non abbiamo bisogno di cercare le quante e quali tabelle sono disponibili a mostrare informazioni, qui possiamo semplicemente sfruttare gli errori ed ottenere direttamente i nomi delle tabelle.

Da questa query ottengo:

… che non è quello che mi aspettavo.

Ciò che l’errore mi dice è che la mia query restituisce più di un solo dato, effettivamente noi un modo per aggirare il problema lo abbiamo già incontrato… sto parlando di LIMIT, vediamo come si presenta la nostra query con l’aggiunta di LIMIT:

… da cui ottengo la prima tabella del database:

… non ci resta che continuare a usare LIMIT fino a raggiungere la tabella che m’interessa:

… e così via fino ad arrivare alla tabella users che credo possa contenere qualcosa d’interessante (avendolo precedentemente fatto, sappiamo sia io che te che la tabella users contiene le colonne con i valori delle credenziali d’accesso, ma per amore della sorpresa fingiamo di non saperlo ancora).

Per ottenere le colonne, vado ad utilizzare:

extractvalue(0x0a,concat(0x0a,( select column_name from information_schema.columns where table_schema=database() and table_name=’users’ LIMIT 0,1 )))

… di cui la parte scritta in rosso non ci rivela nulla di nuovo, andiamo solamente a pescare le colonne dalla tabella users del database precedentemente cercato, nel mio caso è bwapp quindi avrei potuto sostituire database() con il nome vero e proprio del database.

Eseguo la query ricordandomi di cambiare i valori di LIMIT per ottenere uno dopo l’altro le informazioni che cerco (LIMIT 0,1… LIMIT 1,1… LIMIT 2,1…):

M’interessano le colonne login e password, proviamo a ottenerne i valori e vedere se contengono informazioni utili, a questo proposito utilizzerò la seguente query:

extractvalue(0x0a,concat(0x0a,(select concat(login) from users limit 0,1)))

e:

extractvalue(0x0a,concat(0x0a,(select concat(password) from users limit 0,1)))

… queste due query mi mostreranno il primo nome utente (colonna login) e la prima password (colonna password) del database:

… a questo punto non ci resta che passare per un MD5 decrypter come visto precedentemente ed accedere con le credenziali d’accesso trovate.

2.3 Automatizzare la roba noiosa con sqlmap

Tutto ciò che abbiamo appena visto è piuttosto ripetitivo, non sei d’accordo?

Non sarebbe bello se esistesse un applicazione in grado di provare tutte le combinazioni al posto nostro per concludere un attacco con successo? In questa mini-sezione mi propongo di offrirti una breve panoramica generale a sqlmap, un applicazione sviluppata da Bernardo Damele A. G e Miroslav Stampar in grado di fornire una soluzione a questo tipo di problema. Sentiti libero di approfondirne i dettagli nei riferimenti che lascerò nelle ultime pagine di questo documento.

IMPORTANTE: Onde evitare di dilungarmi troppo, non tratterò l’installazione di sqlmap e il modo in cui avviarlo che può variare a seconda del sistema operativo attualmente in uso.

Adesso osserviamo come, con un semplice comando, sqlmap prova tutte le possibili combinazioni al posto nostro su un URL potenzialmente vulnerabile ad attacchi di tipo SQL Injection:

… in cui risk=3 ci indica semplicemente il tipo di query da iniettare, dal più semplice alle query più articolate.

Un’altra caratteristica di sqlmap è quella di potergli passare un file di testo con potenziali URL vulnerabili e lasciare che il programma faccia tutto da solo:

In alternativa, possiamo scegliere di lasciare che sia sqlmap a cercare URL vulnerabili per noi sfruttando le Google dorks, quindi non ci resta che digitare un comando e lasciare tutto nelle mani del programma, vi sconsiglio tuttavia di effettuare questo tipo di test in quanto gli URLs a cui invierete le query non vi appartengono in nessun modo e potreste incorrere in spiacevoli problemi legali.

In conclusione, sqlmap si rivela essere la cura a un bel po’ di mal di testa, nonostante per quanto ho avuto modo di vedere, i test condotti da me medesimo hanno avuto risultati decisamente più soddisfacenti e (anche se difficile da credere) mi hanno fatto risparmiare tempo.

2.4 WAF

In quest’ultima sezione parleremo di Web Application Firewall, in particolare vedremo brevemente alcune tattiche per bypassare questi sistemi di sicurezza che hanno il compito di proteggere un sito web da attacchi come la SQL Injection ma che si rivelano essere, come vedremo, ostacoli facilmente trascurabili.

Supponiamo di aver trovato una vulnerabilità di tipo SQL Injection e di voler tentare una Union Based SQL Injection per estrapolare informazioni dal database. Prepariamo la nostra query, otteniamo il numero di tabelle e quando proviamo a unirle mediante il comando union, riceviamo un errore di questo tipo:

Quesa pagina ha notato il nostro tentativo di ottenere informazioni riservate e ci ha bloccato, diamo un’occhiata alla query che ha dato origine all’errore, con cui dovresti essere già familiare dalla sezione Union SQL Injection

… possiamo facilmente aggirare il problema modificando un po’ la nostra query:

… se tutto è andato bene, il problema dovrebbe essere risolto, in caso contrario non preoccuparti, probabilmente devi solo provare altri tipi di caratteri per ingannare il WAF.

Questa tecnica va a segno la stragrande maggioranza delle volte, tuttavia t’invito ad approfondire la questione nel link che trovi nei riferimenti alla fine del documento.

3. Come difendersi

3.1 Prerequisiti

In questo capitolo tratteremo alcune delle tattiche più utilizzate per la stesura di un codice sicuro e lungi dall’essere manovrato mediante attacchi di SQL Injection. Vi mostrerò delle implementazioni reali in PHP e SQL assumendo che non siate totalmente nuovi ai linguaggi. Non è necessaria un’esperienza quinquennale, una generica idea e i costrutti di base del linguaggio PHP saranno più che sufficienti a permettervi di proseguire senza difficoltà eccessive, SQL ha il vantaggio di essere estremamente semplice da leggere, quindi sono sicuro che a prescindere dal vostro livello, non vi sentirete a disagio nell’analisi di snippet di codice.

3.2 Escape e Binding

Supponiamo di voler creare un sito e di star lavorando sull’area utenti, avremo bisogno di un database che conservi i dati e del linguaggio PHP (o simili) per dinamicizzare la nostra pagina web, una cosa di questo tipo:

… il cui codice è piuttosto elementare:

  1. <?php
  2. // Apri connessione al database.
  3. $conn = mysqli_connect(“localhost”, “root”, “”, “sqlj”);
  4. // Verifica che il form sia stato inviato e analizzane il contenuto.
  5. if (isset($_POST[‘submit’])) {
  6. // Ottieni valori dei campi “username” e “password”
  7.     $username = $_POST[‘username’];  
  8.     $password = $_POST[‘password’]; 
  9. // Inserisci nuovi dati nella tabella “users”
  10.     $query = ‘  
  11.      INSERT INTO users(username, password) 
  12. VALUES(“‘.$username.’”, “‘.$password.’”)  
  13.     ‘;
  14. // Esegui la query, se tutto va bene, stampa un messaggio di successo
  15. // in caso contrario, stampa il messaggio d’errore.
  16.     if (mysqli_query($conn, $query)) {
  17.         echo ‘User added to the Database!’;
  18.     } else {
  19.         echo mysqli_errno($conn) . ‘ : ‘ . mysqli_error($conn);
  20.     }
  21. }
  22. // Chiudi connessione al database.
  23. mysqli_close($conn) ?>
  24. <!– Semplice pagina HTML. –>
  25. <!DOCTYPE html>
  26. <html lang=”en”>
  27. <head>
  28.     <meta charset=”UTF-8″ />
  29.     <meta name=”author” content=”Massimo Piedimonte” />
  30.     <meta name=”description” content=”Esempio non sicuro di storage di dati”>
  31.     <!– Stile della pagina WEB –>
  32.     <link rel=”stylesheet” href=”style.css”>
  33.     <title>SQL Injection</title>
  34. </head>
  35. <body>
  36.     <h1>Sito Web</h1>
  37.     <!– Form dei contatti. –>
  38.     <form action=”<?php htmlentities($_SERVER[‘PHP_SELF’]) ?>” method=”POST”>
  39.         <input type=”text” name=”username” placeholder=”Username” />
  40.         <input type=”password” name=”password” placeholder=”Password” />
  41.         <button type=”submit” name=”submit”>Invia</button>
  42.     </form>
  43. </body>
  44. </html>

L’applicazione è vulnerabile ed il problema risiede proprio nelle porzioni di codice in grassetto. Prima di proporre una soluzione però, verifichiamo il problema attraverso l’aggiunta di qualche carattere strano nei campi di testo, qualora l’applicazione fosse realmente vulnerabile, dovrebbe resituire un errore SQL:

… da cui ottengo, inviando il form:

È tempo di risolvere il problema attraverso l’Escape e il Binding dei parametri.

  • Escape è la fase in cui i valori del campo di testo vengono filtrati, eventuali caratteri non ammessi verranno convertiti in modo tale da non venire interpretati come comandi SQL, ma come semplici stringhe di testo.
  • Binding è la fase in cui prepariamo la nostra query, invece di inserire direttamente i dati lo nella query andremo ad inserire un loro riferimento, in un secondo momento ci occuperemo di inserire i dati reali.

Vediamo concretamente come il nostro codice si modifica una volta apportate determinate misure di sicurezza:

  1. <?php
  2. // Apri connessione al database.
  3. $conn = mysqli_connect(“localhost”, “root”, “”, “sqlj”);
  4. // Verifica che il form sia stato inviato e analizzane il contenuto.
  5. if (isset($_POST[‘submit’])) {
  6. // 1) Fase di Escape.
  7. // —————————
  8. // Ottieni valori dei campi “username” e “password”.
  9. // mysqli_real_escape_string() si occupa di filtrare i
  10. // risultati al posto nostro.
  11.     $username = mysqli_real_escape_string($conn, $_POST[‘username’]);  
  12.     $password = mysqli_real_escape_string($conn, $_POST[‘password’]);
  13. // 2) Fase di Binding.
  14. // —————————-
  15. // Inserisci nuovi dati nella tabella “users”
  16. // I riferimenti di cui parlavamo poc’anzi
  17. // sono i punto-interrogativi (?).
  18.     $query = ‘INSERT INTO users(username, password) VALUES(?, ?)’; 
  19. // Prepara la query con i suoi riferimenti.
  20.     $statement = mysqli_prepare($conn, $query); 
  21. // Esplicita i riferimenti (?).
  22. // Il parametro ‘sss’ indica che stiamo per inserire 2 stringhe di testo
  23. // che corrisponderanno a “username” e “password”.
  24. // Per ulteriori informazioni ti rimando alla documentazione ufficiale:
  25. // http://php.net/manual/en/mysqli-stmt.bind-param.php
  26.     mysqli_stmt_bind_param($statement, ‘ss’, $username, $password);
  27. // Esegui la query, se tutto va bene, stampa un messaggio di successo
  28. // in caso contrario, stampa il messaggio d’errore.
  29.     if (mysqli_stmt_execute($statement)) {
  30.         echo ‘User added to the Database!’;
  31.     } else {
  32.         echo mysqli_errno($conn). ‘ : ‘ .mysqli_error($conn);
  33.     }
  34. }
  35. // Chiudi connessione al database.
  36. mysqli_close($conn);
  37. ?>
  38. <!– Semplice pagina HTML. –>
  39. <!DOCTYPE html>
  40. <html lang=”en”>
  41. <head>
  42.     <meta charset=”UTF-8″ />
  43.     <meta name=”author” content=”Massimo Piedimonte” />
  44.     <meta name=”description” content=”Esempio sicuro di storage di dati”>
  45.     <!– Stile della pagina WEB –>
  46.     <link rel=”stylesheet” href=”style.css”>
  47.     <title>SQL Injection</title>
  48. </head>
  49. <body>
  50.     <h1>Sito Web</h1>
  51.     <!– Form dei contatti. –>
  52.     <form action=”<?php htmlentities($_SERVER[‘PHP_SELF’]) ?>” method=”POST”>
  53.         <input type=”text” name=”username” placeholder=”Username” />
  54.         <input type=”password” name=”password” placeholder=”Password” />
  55.         <button type=”submit” name=”submit”>Invia</button>
  56.     </form>
  57. </body>
  58. </html>

T’invito a prenderti 3 minuti per analizzare le porzioni di codice commentate ed evidenziate in grassetto, tutto ciò che abbiamo fatto è stato mettere a sicuro un sistema utilizzando poche semplici funzioni che l’interfaccia mysqli (così come PDO) ci mette a disposizione.

4. Riferimenti


Stai cercando prodotti per l’hacking, la sicurezza informatica e il penetration testing? Hai bisogno di bonificare il tuo smartphone, il tuo pc o il tuo sito da virus e malware? Devi rintracciare una persona o recuperare delle informazioni urgenti? Devi riprendere possesso di un account, una mail o di una password che ti hanno sottratto? Vuoi acquistare device già configurati per sperimentare tutte le tecniche di hacking in modo facile e veloce? Hai esigenze particolari in ambito software o hardware? Possiamo aiutarti!

Contattaci subito per avere un aiuto immediato : dettagliaci tramite mail o Whatsapp che tipo di supporto ti occorre e ti invieremo un riscontro immediato!

Compila e invia il modulo qui sotto per inviarci subito una richiesta di supporto

Scrivi il tuo indirizzo email qui

Scrivi qui come possiamo aiutarti – ti supportiamo immediatamente per ogni tua esigenza!