2010-08-14 14 views
5

PHP:SQL-injection: questo (oneliner) è sicuro?

 
$SQL = "SELECT goodies FROM stash WHERE secret='" . 
    str_replace("'",'',$_POST['secret']) . 
"'"; 

modo un genio del male hacker di iniettare SQL nel mio SELECT - Come?

+4

È ancora possibile ottenere un'istruzione non valida quando il valore contiene un '\' alla fine che sfuggirà alla chiusura '''. – Gumbo

+3

+1: domanda interessante. Ma indipendentemente dal fatto che sia dimostrato sicuro o meno, non lo consiglierei comunque. :) –

+0

Un errore è OK, a condizione che non influisca sugli utenti onesti. – T4NK3R

risposta

6

ho avuto un pensare a questo per un po 'e non riesco a vedere alcun modo per iniettare SQL in questa informativa.

Una stringa SQL che inizia con una virgoletta singola termina alla successiva quota singola a meno che non sia sfuggita con una barra rovesciata o un'altra citazione (\' o ''). Poiché stai rimuovendo tutte le virgolette singole non ci può essere una citazione doppia. Se si sfugge alla citazione di chiusura si otterrà un errore, ma nessuna iniezione SQL.

Tuttavia questo metodo presenta una serie di inconvenienti:

  • apici singoli nell'input vengono ignorati.
  • Le barre inverse nell'input non vengono gestite correttamente, saranno trattate come codici di escape.
  • Si verifica un errore se l'ultimo carattere è una barra rovesciata.
  • Se in seguito si estende la query per aggiungere un secondo parametro, lo consente un attacco di SQL injection.

Ad esempio:

$SQL = "SELECT goodies FROM stash WHERE secret='" . 
    str_replace("'",'',$_POST['secret']) . 
"' AND secret2 = '" . 
    str_replace("'",'',$_POST['secret2']) . 
"'"; 

Quando viene chiamato con i parametri \ e OR 1 = 1 -- si tradurrebbe in:

SELECT goodies FROM stash WHERE secret='\' AND secret2=' OR 1 = 1 -- ' 

Quale MySQL vedrebbe come qualcosa di simile a questo:

SELECT goodies FROM stash WHERE secret='...' OR 1 = 1 

Anche se è impossibile In questo caso, gli inconvenienti rendono questo non idoneo per un modo generale di evitare l'iniezione SQL.

La soluzione, come già sottolineato, è di utilizzare una dichiarazione preparata. Questo è il modo più affidabile per prevenire attacchi di SQL injection.

+0

Oops, lo faccio (molto!). Ma lo scambio di str_replace con mysql_real_escape_string ($ _ POST ['secret']) lo curerebbe (E la possibilità di causare un errore)? – T4NK3R

+0

@ T4NK3R: fai un sacco? C'è un caso molto raro in cui mysql_real_escape_string non funziona correttamente: http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared- Statements.html. Statem preparato ents è il modo migliore, ma mysql_real_escape_string dovrebbe funzionare anche se fatto correttamente. –

+0

Do: aggiungi coppie extra chiave = valore (per lo più interi ma "induriti" da semplici (int) cast). BTW: my php-source è in UTF-8 e anche dbConnection (mysql_set_charset ('utf8', $ dbCon);) - Off per leggere il tuo link ora! – T4NK3R

14

Perché non userete mysql_real_escape_string() o anche meglio - istruzioni preparate? La tua soluzione sembra sciocca.

+9

+1 per la dichiarazione preparata. –

+0

distaccato ... in particolare per le istruzioni preparate – prodigitalson

+0

Sto cercando di mantenerlo il più "snello" possibile ... – T4NK3R

-1

Perché non utilizzare mysql_escape_string? E sì, poteva, aggiungendo " invece di ' e in più, questa query ti darà un errore, immagino.

+0

Un errore è OK, a condizione che non influisca sugli utenti onesti. – T4NK3R

+0

Penso che la query 'SELECT goodies FROM stash WHERE secret = '"' 'non è un problema.La doppia citazione non terminerà la stringa.Quale tipo di errore ti stai riferendo a? –

0

Può essere. Il modo migliore è:

$query = sprintf("SELECT goodies FROM stash WHERE secret='%s'", 
addcslashes(mysql_real_escape_string($_POST['secret']),'%_')); 
+0

Non hai bisogno per sfuggire '%' e '_' dato che non stai usando' LIKE'. – Gumbo

+0

Sì, la funzione addcslashes è opzionale – barroco

+0

Sto costruendo l'istruzione dinamicamente (per una ricerca con molte opzioni), quindi preferirei mantenere ogni coppia chiave-valore insieme, costruendo l'istruzione in una stringa mentre procedo: – T4NK3R