2013-03-21 25 views
56

Per iniziare, sono consapevole che le query con parametri sono l'opzione migliore, ma mi sto chiedendo cosa rende vulnerabile la strategia che presento. La gente insiste che la soluzione sottostante non funziona, quindi sto cercando un esempio del perché non lo farebbe.In che modo il risanamento che sfugge alle virgolette singole può essere sconfitto dall'iniezione SQL in SQL Server?

Se SQL dinamico è incorporato nel codice utilizzando il seguente escape prima di essere inviato a un server SQL, quale tipo di iniezione può sconfiggere questo?

string userInput= "N'" + userInput.Replace("'", "''") + "'" 

Una domanda simile è stato risposto here, ma non credo nessuna delle risposte sono applicabili qui.

L'escape della quota singola con una "\" non è possibile in SQL Server.

ritengo SQL contrabbando con Unicode (illustrato here) verrebbe ostacolato dal fatto che la stringa prodotta è contrassegnato come Unicode dal N precede la sola offerta. Per quanto ne so, non ci sono altri set di caratteri che SQL Server traduca automaticamente in una singola citazione. Senza una singola citazione senza escape, non credo che l'iniezione sia possibile.

Non credo Il troncamento di stringa è anch'esso un vettore valido. SQL Server certamente non eseguirà il troncamento poiché la dimensione massima per un nvarchar è 2 GB according to microsoft. Una stringa da 2 GB non è fattibile nella maggior parte delle situazioni e impossibile nella mia.

Secondo Ordine iniezione potrebbe essere possibile, ma è possibile se:

  1. Tutti i dati che vanno in cui il database è sterilizzate con il metodo di cui sopra
  2. valori dalla banca dati non vengono mai aggiunti in SQL dinamico (perché lo faresti mai comunque, quando puoi semplicemente fare riferimento al valore della tabella nella parte statica di qualsiasi stringa SQL dinamica?).

Non sto suggerendo che sia meglio o un'alternativa all'utilizzo di query con parametri, ma voglio sapere come ciò che ho delineato è vulnerabile. Qualche idea?

+1

No. Sei ancora suscettibile di attacchi in forma: ' "SELECT * FROM MyTable WHERE campo =" + userInput' quando' 'userInput' è 0 ; DROP TABLE OhNo; '. – Yuck

+8

Questo non ha senso. Nell'esempio sopra, l'input dell'utente verrebbe sterilizzato su N'0; DROP TABLE OhNo; ' prima di essere mai giustiziato. – GBleaney

+3

Questo vale solo per la sanitizzazione di variabili di stringa. Cose come "int" non hanno bisogno di essere sanificate se vengono lanciate come int prima di essere aggiunte alla query. In ogni caso, sto solo chiedendo di disinfettare le stringhe in questo momento. Inoltre, non c'è bisogno di essere maleducati qui. Se riesci a pensare a un modo in cui questo non è sicuro, mi piacerebbe saperlo. – GBleaney

risposta

33

Ci sono alcuni casi in cui questa funzione di escape fallirà. Il più evidente è quando una singola citazione non viene utilizzato:

string table= "\"" + table.Replace("'", "''") + "\"" 
string var= "`" + var.Replace("'", "''") + "`" 
string index= " " + index.Replace("'", "''") + " " 
string query = "select * from `"+table+"` where name=\""+var+"\" or id="+index 

In questo caso, si può "rompere" con un doppio apice, un back-tick. Nell'ultimo caso non c'è nulla da "scoppiare", quindi puoi semplicemente scrivere 1 union select password from users-- o qualsiasi altro payload sql desideri dall'attaccante.

La condizione successiva in cui viene se è preso un sub-string questa funzione escape fallirà dopo la stringa è sfuggito (e vulnerabilità sì ho trovato come questo in natura):

string userPassword= userPassword.Replace("'", "''") 
string userName= userInput.Replace("'", "''") 
userName = substr(userName,0,10) 
string query = "select * from users where name='"+userName+"' and password='"+userPassword+"'"; 

In In questo caso, il nome utente abcdefgji' verrà convertito in abcdefgji'' dalla funzione di escape e quindi tornato in abcdefgji' prendendo la sottostringa. Questo può essere sfruttato impostando il valore della password su qualsiasi istruzione sql, in questo caso or 1=1-- verrà interpretato come sql e il nome utente verrà interpretato come abcdefgji'' and password=. La query risultante è la seguente:

select * from users where name='abcdefgji'' and password=' or 1=1-- 

T-SQL e altre tecniche di iniezione sql avanzate dove già menzionato. Advanced SQL Injection In SQL Server Applications è un ottimo documento e dovresti leggerlo se non lo hai già fatto.

Il problema finale è gli attacchi Unicode. Questa classe di vulnerabilità si presenta perché la funzione di escape non è a conoscenza della codifica a byte multipli, e questo può essere used by an attacker to "consume" the escape character. Non è utile mantenere una "N" nella stringa, poiché ciò non influisce sul valore dei caratteri multibyte più avanti nella stringa. Tuttavia, questo tipo di attacco è molto raro perché il database deve essere configurato per accettare stringhe unicode GBK (e non sono sicuro che MS-SQL possa farlo).

L'iniezione del codice di secondo ordine è ancora possibile, questo modello di attacco viene creato affidandosi a origini dati controllate dagli autori di attacchi. L'escape è usato per rappresentare i caratteri di controllo come letterali dei loro personaggi. Se lo sviluppatore si dimentica di sfuggire a un valore ottenuto da un select e quindi utilizza questo valore in un'altra query, quindi bam, l'utente malintenzionato avrà a sua disposizione una virgoletta singola letterale.

Testare tutto, non fidarsi di nulla.

+1

Mentre sono d'accordo a giocare con la sicurezza, invece, la parametrizzazione della query è negativa, se si legge attentamente la sua domanda, ha preso nota di diversi passaggi che avrebbe intrapreso per "garantire" la sicurezza. 1) si sta accertando che un valore numerico sia effettivamente un valore numerico, quindi l'iniezione di id nel tuo esempio non riuscirebbe 2) sta chiedendo di SQL Server che accetta solo "" come delimitatore di stringhe. Usare tick o virgolette non aiuterebbe l'aggressore –

+0

@Nikola Radosavljević sì, ma i back-tics e la mancanza di virgolette possono ancora essere un problema a seconda di come ha impiantato questo assegno. Chiaramente questo post è dal punto di vista di un attaccante non un difensore. La difesa è ben nota e poco interessante. – rook

+2

Il codice nella domanda non è vulnerabile all'attacco. Questa è una buona risposta come guida generale per l'escape di stringhe letterali ed è sia corretta che interessante; ma gli scenari elencati non sarebbero in grado di compromettere la linea di codice nella domanda originale. Per quanto riguarda gli attacchi di seconda mano, potrebbe accadere che il testo sia stato originariamente inserito con un parametro o come letterale se contiene un carattere di citazione. – Rob

8

Using query parameters è migliore, più semplice e più veloce rispetto alle citazioni di escape.


Re tuo commento, vedo che ha riconosciuto la parametrizzazione, ma merita di essere sottolineato. Perché dovresti usare l'escaping quando potresti parametrizzare?

In Advanced SQL Injection In SQL Server Applications, cercare la parola "sostituisci" nel testo e da quel punto in poi leggere alcuni esempi in cui gli sviluppatori hanno inavvertitamente consentito attacchi di SQL injection anche dopo aver ignorato l'input dell'utente.


C'è un caso limite in cui fuoriesce citazioni con \ comporta una vulnerabilità, perché il \ diventa metà di un carattere multi-byte valido per alcuni insiemi di caratteri. Ma questo non è applicabile al tuo caso poiché \ non è il carattere di escape.

Come altri hanno sottolineato, è possibile che si stia aggiungendo contenuto dinamico all'SQL per qualcosa di diverso da un letterale di stringa o da un letterale di data. Gli identificativi di tabella o colonna sono delimitati da " in SQL o [] in Microsoft/Sybase. Le parole chiave SQL, ovviamente, non hanno alcun delimitatore. Per questi casi, consiglio di aggiungere alla whitelist dei valori da interpolare.

La linea di fondo è che la fuga è una difesa efficace, se è possibile assicurarsi di farlo in modo coerente. Questo è il rischio: che uno degli sviluppatori della tua applicazione potrebbe omettere un passo e fare un po 'di interpolazione delle stringhe in modo non sicuro.

Ovviamente lo stesso vale per altri metodi, come la parametrizzazione. Sono efficaci solo se li fai in modo coerente. Ma trovo che sia più facile usare i parametri più rapidamente, piuttosto che capire il giusto tipo di escape. E gli sviluppatori hanno maggiori probabilità di utilizzare un metodo che è conveniente e non li rallenta.

+2

Come dichiaro nella prima riga del mio post, ne sono ben consapevole. Sto solo chiedendo se c'è qualche ragione specifica per cui quello che ho delineato non è sicuro. – GBleaney

+1

Questa è una grande risorsa, ma i possibili problemi suggeriti qui non sono davvero un problema qui. Innanzitutto, la costruzione di virgolette usando il metodo "char (0x63)" è inutile, perché quella dichiarazione verrà interpretata come una stringa e non verrà eseguita. Per quanto riguarda l'iniezione SQL del secondo ordine, l'ho già trattato nel post originale. – GBleaney

3

L'iniezione SQL si verifica se gli input forniti dall'utente vengono interpretati come comandi. Qui comando significa tutto ciò che non è interpretato come un valore riconosciuto data type letterale.

Ora se si sta utilizzando l'input dell'utente solo in letterali di dati, in particolare solo in stringhe letterali, l'input dell'utente verrà interpretato solo come qualcosa di diverso dai dati stringa se sarebbe in grado di lasciare il contesto letterale stringa. Per i caratteri letterali stringa stringa o Unicode, è la virgoletta singola che racchiude i dati letterali mentre le virgolette singole incorporate devono essere rappresentate con due virgolette singole.

Pertanto, per lasciare un contesto letterale stringa, è necessario fornire una virgoletta singola (sic) come due virgolette singole vengono interpretate come dati letterali stringa e non come il delimitatore fine letterale stringa.

Quindi, se si sostituiscono virgolette singole nei dati forniti dall'utente da due virgolette singole, sarà impossibile per l'utente lasciare il contesto letterale della stringa.

2

Probabilmente non esiste un modo sicuro al 100% se si esegue la concatenazione di stringhe. Quello che puoi fare è provare a controllare il tipo di dati per ciascun parametro e se tutti i parametri superano tale convalida, procedi con l'esecuzione. Ad esempio, se il parametro deve essere di tipo int e stai ricevendo qualcosa che non può essere convertito in int, basta rifiutarlo.

Questo non funziona se si accettano i parametri nvarchar.

Come già sottolineato da altri. Il modo più sicuro è utilizzare la query con parametri.

16

Con alcune clausole aggiuntive, l'approccio sopra riportato non è vulnerabile all'iniezione SQL. Il principale vettore di attacco da considerare è SQL Smuggling. Il contrabbando SQL si verifica quando i caratteri unicode simili vengono tradotti in modo inatteso (ad esempio "cambiando a"). Esistono diverse posizioni in cui uno stack di applicazioni potrebbe essere vulnerabile a SQL Smuggling.

  • fa il linguaggio di programmazione stringhe Unicode maniglia in modo appropriato? Se la lingua non è sensibile all'unicode, potrebbe erroneamente identificare un byte in un carattere unicode come una virgoletta singola e scappare.

  • La libreria del database client (ad esempio ODBC, ecc.) Gestisce le stringhe Unicode in modo appropriato? System.Data.SqlClient nel framework .Net, ma che dire delle vecchie librerie dell'era di Windows 95? Esistono effettivamente librerie ODBC di terze parti. Cosa succede se il driver ODBC non supporta unicode nella stringa di query?

  • Il DB gestisce correttamente l'ingresso? Le versioni moderne di SQL sono immuni se si presume che si stia utilizzando N '', ma per quanto riguarda SQL 6.5? SQL 7.0? Non sono a conoscenza di particolari vulnerabilità, tuttavia questo non era nel radar per gli sviluppatori negli anni '90.

  • Overflow del buffer? Un'altra preoccupazione è che la stringa citata è più lunga della stringa originale. In quale versione di Sql Server è stato introdotto il limite di 2 GB per l'input? Prima di quello che era il limite? Nelle versioni precedenti di SQL, cosa accadeva quando una query superava il limite? Esistono limiti sulla lunghezza di una query dal punto di vista della libreria di rete? O sulla lunghezza della stringa nel linguaggio di programmazione?

  • Esistono impostazioni della lingua che influiscono sul confronto utilizzato nella funzione Sostituisci()? .Net esegue sempre un confronto binario per la funzione Sostituisci(). Sarà sempre così? Cosa succede se una versione futura di .NET supporta l'override di quel comportamento a livello di app.config? Cosa succede se abbiamo usato un'espressione regolare invece di Replace() per inserire una virgoletta singola? Le impostazioni locali del computer influenzano questo confronto? Se si verifica un cambiamento nel comportamento, potrebbe non essere vulnerabile a SQL injection, tuttavia, potrebbe aver inavvertitamente modificato la stringa modificando un carattere univoco simile a una virgoletta singola in una singola virgoletta prima di raggiungere il DB.

Quindi, supponendo che si sta utilizzando la funzione System.String.Replace() in C# sulla versione corrente del .Net con il built-in libreria SqlClient contro una (2005-2012) la versione corrente di SQL server, quindi il tuo approccio non è vulnerabile. Quando inizi a cambiare le cose, non è possibile fare promesse. L'approccio di query parametrizzato è l'approccio corretto per l'efficienza, per le prestazioni e (in alcuni casi) per la sicurezza.

AVVISO I commenti sopra riportati non costituiscono un'approvazione di questa tecnica. Ci sono molti altri buoni motivi per cui questo è l'approccio sbagliato alla generazione di SQL. Tuttavia, la loro descrizione è al di fuori dello scopo di questa domanda.

NON UTILIZZARE QUESTA TECNICA PER UN NUOVO SVILUPPO.

NON utilizzare questa tecnica per un nuovo sviluppo.

NON utilizzare questa tecnica per un nuovo sviluppo.

+0

Se non questa tecnica, cosa dovrei usare per 'CREATE LOGIN' in un nuovo sviluppo? – binki

3

SQL Injection può avvenire tramite unicode. Se il web app ha un URL simile a questo:

http://mywebapp/widgets/?Code=ABC

che genera SQL come select * from widget dove Codice = 'ABC'

ma un hacker entra in questo:

http://mywebapp/widgets/?Code=ABC%CA%BC;drop tavolo widgets--

l'SQL sarà simile a seleziona * dai widget dove Code = 'ABC'; drop widget tabella-- '

e SQL Server eseguiranno due istruzioni SQL. Uno per fare la selezione e uno per fare la goccia. Il tuo codice converte probabilmente l'% codificato in url CA% BC in Unicode U02BC che è un "Modificatore di lettere apostrofo". La funzione Replace in .Net NON la tratterà come una singola citazione. Tuttavia Microsoft SQL Server lo considera come una singola citazione.Ecco un esempio che probabilmente permetterà di SQL Injection:

string badValue = ((char)0x02BC).ToString(); 
badValue = badValue + ";delete from widgets--"; 
string sql = "SELECT * FROM WIDGETS WHERE ID=" + badValue.Replace("'","''"); 
TestTheSQL(sql); 
+0

Funzionerà: string sql = "SELECT * FROM WIDGETS WHERE ID = '" + badValue.Replace ("'", "''") + "'"; – linjunhalida

Problemi correlati