Iniezione SQL: perché le citazioni di escape non sono più sicure?

77

SQL raw

Quando scrivi SQL - per tutto ciò che richiede veramente input umani, sono state fatte molte cose per evitare l'iniezione.

Tutti quelli che hanno sentito parlare di SQL injection sanno che (sto per usare PHP come esempio) fare qualcosa del genere non è sicuro:

$sql = "SELECT * FROM 'users' 
.  WHERE 'userName' = "{$_POST["username"]}" 
.  AND 'pass' = "{$_POST["pass"]}";";

Magic

Poi, naturalmente, a qualcuno è venuto in mente l'idea di usare "virgolette magiche" per gestire l'input del programma che non è stato disinfettato correttamente e messo direttamente in sql come risultato di cattive pratiche. Questo non ha realmente risolto il problema con SQL injection, ma ha significato che tutti gli input dell'utente sono stati storpiati.

Aggiunta di barre

Quindi, alcune persone hanno disattivato le virgolette magiche. Quindi, hanno analizzato l'input dell'utente prima del punto di SQL attraverso addslashes() che in teoria sfugge a tutte le virgolette e il tuo hacker non può fare ' OR 1=1 , ma anche la documentazione di addslashes è che non devi usare addslashes, dice che usa la funzione specifica del database come mysql_real_escape_string() , ma si dice che questo non sia abbastanza per alcuni.

Aggiunta di barre specifiche al database

Quindi, non possiamo usare% specifico di DBMS *_real_escape_string , non possiamo usare add slashes , la cosa "virgolette" ha causato un sacco di problemi, e il web è pieno di citazioni di parole brevi come:

"A dedicated hacker will find a way to jump through your quote-escaping loops, just use the DBAL prepared statements" - John Q any programmer

Okay, quindi mi hai spaventato abbastanza da usare le istruzioni preparate e un DBAL. Non ha davvero spiegato nulla, ma suona bene perché l'ho sentito molto.

Dichiarazioni preparate

Quindi ora stiamo usando PDO, o un DBAL da un framework, o qualcos'altro che avvolge tutto il nostro sql e si assicura che qualcuno non possa eseguire un'iniezione sql.

La mia domanda è fondamentalmente un "perché no?", non un "cosa dovrei usare?". Il web è pieno di persone che ti dicono di usarlo o di usarlo o qualunque , ma nessuna spiegazione del perché queste cose devono accadere.

Domande dirette

Domande puntate (promemoria, sto chiedendo di SQL, PHP era un linguaggio di esempio a causa della sua cattiva reputazione su SQL, i concetti sono universali):

  1. Perché non possiamo sfuggire a tutti gli input dell'utente usando "magic"?
  2. Perché non sono stati aggiunti "abbastanza buoni"?
  3. Cosa c'è di sbagliato nell'usare funzioni di escape specifiche del DB, e perché è stato meglio di addslashes?
  4. Perché le dichiarazioni preparate con framework e PDO vengono considerate il gold standard di SQL? Perché stanno meglio? Perché non posso fare un'iniezione SQL con questi, dove potrei avere con i mezzi precedentemente citati? Può un programmatore che in qualche modo riesca ancora a rovinare tutto? Cosa dovrebbero cercare?
  5. Altri dubbi che non ho sollevato?
posta Incognito 06.05.2011 - 16:44
fonte

7 risposte

52

Why can't we escape all user input using "magic"?

Nel momento in cui viene applicata la magia, non si sa dove finiranno i dati. Quindi le virgolette stanno distruggendo dati che, a meno che non siano scritti senza caratteri di escape in un database.

Potrebbe essere usato solo nella risposta HTML inviata al client. Pensa a una forma che non è stata completamente riempita e viene quindi mostrata di nuovo all'utente. Con le virgolette magiche, i dati inseriti al primo tentativo saranno ora sottoposti a escape SQL, il che è privo di significato su una pagina HTML. Ancora peggio: al secondo invio i dati vengono nuovamente sottoposti a SQL di escape.

Why wasn't addslashes "good enough"?

Ha problemi con i caratteri multibyte:

' 27
\ 5c
뼧 bf 5c

Questi sono due byte, ma solo un carattere Unicode.

Poiché addslashes non sa nulla di Unicode, converte l'input bf 27 in bf 5c 27 . Se viene letto da un programma in grado di riconoscere Unicode, è visto come 뼧 '. Boom.

C'è una buona spiegazione di questo problema su link

Whats wrong with using DB-specific escape functions, and why was it better than addslashes?

Sono migliori perché garantiscono che l'escaping interpreti i dati nello stesso modo in cui funziona il database (vedi l'ultima domanda).

Dal punto di vista della sicurezza, sono a posto se li usi per ogni singolo input di database. Ma hanno il rischio che tu possa dimenticare entrambi da qualche parte.

Modifica : come aggiunto getahobby: O che usi xxx_escape_strings per i numeri senza aggiungere virgolette attorno a loro nell'istruzione SQL e senza assicurarti che siano numeri effettivi mediante la fusione o la conversione dell'input nell'appropriato tipo di dati / Modifica

Da un punto di vista dello sviluppo del software sono cattivi perché rendono molto più difficile aggiungere il supporto per altri software per server di database SQL.

Why are prepared statements with frameworks and PDO being hailed as the gold standard of SQL? Why are they better?

I PDO sono per lo più una buona cosa per ragioni di progettazione del software. Rende molto più semplice il supporto di altri software per server di database. Ha un'interfaccia orientata agli oggetti che astrae molte delle incompatibilità specifiche del database.

Why can't I do an SQL injection with these [prepared statements], where as I COULD have with the previously mentioned means?

La parte " query costante con parametri variabili " delle istruzioni preparate è ciò che è importante qui. Il driver del database sfuggirà automaticamente a tutti i parametri senza che lo sviluppatore debba pensarci.

Le query parametrizzate sono spesso più facili da leggere rispetto alle normali query con parametri di escape per motivi sintattici. A seconda dell'ambiente, potrebbero essere un po 'più veloci.

Utilizzare sempre istruzioni preparate con parametri è qualcosa che può essere convalidato da strumenti di analisi del codice statico . Una chiamata mancante a xxx_escape_string non viene individuata facilmente e in modo affidabile.

Can a programmer not somehow manage to still screw this up? What should they look out for?

Le "istruzioni preparate" implicano che sono costanti . Generazione dinamica di istruzioni preparate, in particolare con l'input dell'utente, hanno ancora tutti i problemi di iniezione.

    
risposta data 07.05.2011 - 01:16
fonte
13

[1.] Why can't we escape all user input using "magic" ?

Perché le virgolette sono rotte su due fronti:

  1. Non tutti i dati $ _ (REQUEST / GET / POST) vanno nel DB. E per farti capire, devi sfuggire l'input.
  2. Sono l'equivalente di addslashes (vedi la mia nota su [2.]), quindi non sono effettivamente sicuri.

[2.] Why wasn't addslashes "good enough"?

Ci sono molti modi per uscire dalla restrizione di addslashes , quindi, è fondamentalmente imperfetto, comunque tu provi ad usarlo.

[3.] Whats wrong with using DB-specific escape functions, and why was it better than addslashes?

Niente di veramente. Questo è semplicemente il mantra sul perché i PDO / preparati sono "migliori". Sono modo migliori di addslashes poiché si prendono cura di molti fattori, inclusa la codifica. Ecco un piccolo segreto; PDO li usa internamente, ma non addslashes ...

[4.] Why are prepared statements with frameworks and PDO being hailed as the gold standard of SQL? Why are they better? Why can't I do an SQL injection with these, where as I COULD have with the previously mentioned means?

Sono non lo standard d'oro , sono non "più" sicuri di funzioni specifiche di DB e tu puoi eseguire l'iniezione SQL con questi pure. E no, non puoi fare un'iniezione SQL con un input opportunamente igienizzato.

Come con tutte le tecnologie là fuori, gli sviluppatori tendono a sviluppare tendenze religiose (fanatiche?) per qualsiasi cosa "nuova". Questo è il motivo per cui consulti Zend Certified Engineers (TM), esperto, che ti obbliga a passare a istruzioni preparate.

La realtà, tuttavia, è che tutto dipende dal sapere cosa stai facendo. Se stai caricando un articolo con il suo ID numerico, non hai bisogno di alcun tipo di escape, anche meno PDO. Devi semplicemente assicurarti che l'ID sia effettivamente un numero intero.

Da una prospettiva più realistica, la regola generale non è usare istruzioni DOP / preparate, ma per usare le funzioni giuste, vale a dire, deve usare mysql_real_escape_string() invece di addslashes() o mysql_escape_string() .

[5.] Can a programmer not somehow manage to still screw this up? What should they look out for?

Certo! Ma non è "cosa cercare", ma piuttosto "sai cosa stai facendo".

Come vedi, eval($_GET['code']) * è del tutto legittimo se usato nel posto giusto (come un PHP Test Runner locale).

Se si utilizza un ORM per eseguire una query condizionale, si immette direttamente il codice, quindi potrebbe esserci una possibilità di ottenere l'iniezione SQL se non lo si fa correttamente (dipende dall'ORM in questione). (Ipotetico) Esempio:

// update() sets the value of a column given a condition
//
//                         .--escaping is automatic here
//                         |                           .--hypothetical SQL injection
//                         v                           v
Db()->update('name',$_GET['newname'])->where(' id = '.$_GET['id']);

(* Posso solo immaginare gli innumerevoli professionisti che sbattono la testa su questo)

    
risposta data 08.05.2011 - 09:45
fonte
9

Alla fine della giornata è necessario eseguire l'escape degli input per proteggere le query da SQL Injection. Le librerie di query parametrizzate come PDO e ADODB utilizzano l'escaping , tutto ciò che fanno è applicare questa pratica in modo implicitamente sicuro. Con constrast magic_quotes_gpc fa NON , questo è un approccio fondamentalmente errato al problema.

1) La fuga può essere problematica se non capisci cosa stai facendo. Questo tipo di problema è ancora sfruttabile se magic_quotes_gpc è abilitato.

mysql_query("select * from users where id=".addslashes($_GET[id]));

Exploit PoC: link )

patch:

mysql_query("select * from users where id='".addslashes($_GET[id])."'");

Lezione: Non hai bisogno di virgolette per sfruttare SQL injection.

2) Diciamo che sfuggi solo ai segni di virgolette:

mysql_query("select * from users where name='".htmlspecialchars($_GET[name],ENT_QUOTES)."' and id='".htmlspecialchars($_GET[id],ENT_QUOTES)."'");

Exploit PoC: link \ & id = + o + sleep (30) / *

Patch:

mysql_query("select * from users where name='".addslashes($_GET[name])."' and id='".addslashes($_GET[id])."'");

Lezione : i backslash sono ugualmente pericolosi come virgolette.

3) E riguardo la codifica della lingua?

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".addslashes($_GET[name])."'");

PoC Exploit: http: //localhost/vuln.php? name =% bf% 27 = sleep (30) / *

Patch:

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".mysql_real_escape_string($_GET[name])."'");

Conclusione:

L'escape è assolutamente necessario per evitare l'iniezione sql in un'applicazione. In PHP PDO e ADOB sono grandi librerie di query parametrizzate che impongono l'escaping dell'input dell'utente. Il problema è che molti programmatori non capiscono cosa sia l'escape. Avere una libreria per applicare questa politica di sicurezza è il miglior metodo di difesa, perché non è necessario comprendere le regole di escape.

    
risposta data 07.05.2011 - 22:25
fonte
5

Informazioni sulle funzioni di escape specifiche del DB. Esistono molti scenari in cui può verificarsi l'iniezione SQL, anche se mysql_real_escape_string () è stato utilizzato. LIMIT e ORDER BY sono davvero difficili!

Questi esempi sono vulnerabili all'iniezione SQL:

$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
$sql = "SELECT userid, username FROM sql_injection_test LIMIT $offset, 10";

o

$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
$sql = "SELECT userid, username FROM sql_injection_test ORDER BY '$order'";

In entrambi i casi non è possibile utilizzare 'per proteggere l'incapsulamento.

fonte : L'Inaspettata SQL Injection (quando la fuga non è sufficiente) < - Leggi questo

    
risposta data 17.08.2011 - 23:15
fonte
4

I filtri possono essere ignorati e i dati che vanno nelle istruzioni SQL possono provenire da più punti rispetto all'input dell'utente. I punti di ingresso in un source / sink influenzato da SQL possono essere memorizzati (ordine superiore), come un esempio, ma chiaramente i parametri GET HTTP ei parametri POST dai moduli HTML non sono gli unici modi di input dell'utente.

Le query parametrizzate non rendono necessariamente le tue istruzioni SQL libere da iniezioni. Richiedono inoltre il binding variabile, la rimozione delle operazioni di stringa / concatenazione e l'eliminazione di determinati problemi di sicurezza con una vasta gamma di clausole SQL.

La maggior parte degli sviluppatori dimentica anche di controllare i componenti di terze parti e altre dipendenze per problemi di iniezione SQL, e talvolta non si rende conto che queste inclusioni potrebbero rendere vulnerabile il proprio codice.

La cosa migliore da fare è assumere una società di consulenza sulla sicurezza delle applicazioni per preparare le applicazioni per la preparazione alla produzione e addestrare i tuoi team appdev sulla costruzione di controlli di sicurezza delle applicazioni nella loro tecnologia di processo e di sviluppo.

    
risposta data 06.05.2011 - 18:57
fonte
3

Espandere la risposta di Hendrick. È facile pensare a real_escape_string come a un proiettile magico quando in realtà non lo è. Ho visto persone che usano quella funzione quando vogliono usare intval o lanciare l'input su un intero. Puoi comunque essere iniettato se usi la stringa di escape nel contesto sbagliato.

    
risposta data 07.05.2011 - 02:00
fonte
-3

Dato che il punto è aiutarti a imparare come scrivere codice decente e non solo copiare una ricetta, lascerò alcuni suggerimenti.

  • Se lasciamo la codifica, ci sono molti modi per iniettare sql e non tutti richiedono di aggiungere "o" o ", quindi Addslash è fondamentalmente una soluzione zoppa usata dagli sviluppatori zoppi e non specializzati ... . (Quelli da cui non dovresti leggere il codice)

  • Questo non accade molto, ma in realtà c'è un vettore in cui l'attaccante può sfruttare una dichiarazione preparata, in alcuni motori db. Non è comune, ma puoi ricordare che l'istruzione preparata usa una dichiarazione ma con il tipo di colonna data metatdata, dimensione ....

  • Altro solito errore di lame sta gestendo le ricerche nelle query con Mi piace ... Se scopri come funziona puoi fare alcune cose interessanti ...

Fai la tua ricerca, non fidarti mai di un input, non usare mai nulla di diverso da una dichiarazione preparata, ignora tutti quelli che ti dicono di usare escape fu ...

E dovresti essere al sicuro, ricorda che non ha senso ottenere qualcosa di diverso da quello che ti aspetti, così strong api tipizzate è tuo amico;).

    
risposta data 09.10.2014 - 00:48
fonte

Leggi altre domande sui tag