Come una connessione al database rende mysqli_real_escape_string più sicuro?

1

Sto imparando PHP + MySQL e ho osservato che la funzione mysqli_real_escape_string in PHP richiede un identificatore per una connessione MySQL. Da alcune ricerche ho scoperto che ha qualcosa a che fare con i caratteri charset e multibyte, ma non lo capisco completamente. Quindi la mia domanda è come la connessione al database aiuta a rendere la funzione mysqli_real_escape_string più sicura?

    
posta VarunAgw 18.12.2013 - 12:02
fonte

2 risposte

3

Come nota, prima di dire qualcosa su questo problema: per favore considera di passare a MySQLi o PDO con query parametrizzate. Non solo sono un ordine o grandezza più sicuri, ma sono più facili da utilizzare e pienamente supportati. Le vecchie funzioni mysql_ sono ora considerate al termine del ciclo di vita e saranno presto deprecate. (mi dispiace, ho perso il i dal tuo post originale ... maledette chiamate procedurali!)

MySQL opera su stringhe. Le stringhe sono due cose: una sequenza di byte e una sequenza di caratteri. Il modo in cui queste due sequenze si mappano è chiamato set di caratteri, che è specificato da una codifica.

Ad esempio, ASCII mappa lettere, numeri, simboli e caratteri di controllo sui valori di byte da 0 a 127. ASCII estesi quindi aggiunge più caratteri per i valori da 128 a 255. Altre codifiche, come la famiglia UTF (es. UTF- 8) utilizzare byte singoli o multipli per codificare caratteri diversi. Ad esempio, i caratteri UTF-16 possono essere codificati come uno o due codepoint di 2 byte (vale a dire ogni carattere è codificato come 2 o 4 byte).

La parte interessante si verifica quando si assume un set di caratteri o una codifica, ma i dati sottostanti vengono effettivamente codificati in modo diverso. Ad esempio, il carattere CJK est-asiatico per "acqua" è 水, che è definito in UTF-16 come U + 6C34. Questo codifica per 34 6C in UTF-16LE. Ora, se accidentalmente supponiamo che i dati che ci sono stati consegnati siano ASCII, dovremmo decodificare questo come "4l" piuttosto che il carattere Unicode corretto.

Ora, cosa succede se l'applicazione front-end (in questo caso PHP) è stata configurata per utilizzare l'ASCII esteso, ma le regole di confronto del database sono state impostate su UTF-8 (ad es. utf8_general_ci) e il computer dell'utente è stato configurato per utilizzare il Windows CP1251 Codepage in cirillico? In un mondo ideale, ogni sistema riconoscerebbe i requisiti dell'applicazione di destinazione e convertirà in modo appropriato. Sfortunatamente questo non è un mondo ideale. I byte sottostanti che rappresentano i caratteri cirillici verrebbero probabilmente trasformati in caratteri ASCII sulla loro strada nella webapp di PHP. Quindi, qualsiasi carattere elevato (128-255) potrebbe re-mappare a sequenze di byte diverse quando i caratteri ASCII vengono convertiti in UTF-8, o potrebbe addirittura formare caratteri completamente nuovi se accidentalmente tradotti in codice in codepoint UTF-8. In alcuni casi, esistono regole speciali che causano determinati codepoint sequenziali (ad esempio segni diacritici) per essere combinati in caratteri speciali.

In breve: la codifica dei caratteri è voodoo . Questo è un territorio serio "qui sia i draghi". Se riesci a ottenere una risposta sensata da chiunque abbia scritto una vera libreria di stringhe prima (di solito scarabocchiano "cthulhu ebcdic fhtagn" sul tuo viso con un pennarello magico e se ne allontani misteriosamente) allora loro probabilmente ti dirò alcune cose veramente disgustose sull'abominio che è il nostro linguaggio umano.

Perché questo è importante per cose come mysql_escape_string ? Bene, diciamo che la tua app PHP è in modalità UTF-8, ma il tuo server MySQL è in esecuzione in modalità ASCII. Il tuo utente digita un carattere ∻ ( U + 223B ) e la tua funzione di fuga dice "Spara bene, mi sta bene, ho solo cura di citazioni e cose ". Il tuo server MySQL quindi guarda quei byte sottostanti ... oh, risulta che 22 3B è una codifica di "; in ASCII. Ops!

Questo peggiora quando ti ricordi di quelli che combinano trucchi. Puoi fare cose come applicare un segno diacritico a un pezzo di punteggiatura, o dare uno schiaffo alla punteggiatura nel mezzo di un testo arabo, e potrebbe essere combinato in un carattere "combinato" con un codepoint completamente diverso quando viene ricodificato . Questo è importante quando utilizzi diversi moderni formati di codifica come UTF-8 e UTF-16 insieme.

La funzione mysql_real_escape_string tenta di salvarci da questo inferno controllando correttamente la stringa una volta che è stata ricodificata nella codifica selezionata del server MySQL di destinazione. Ha bisogno di un riferimento alla connessione per recuperare questi metadati dal server.

La cosa più misericordiosa del mondo, penso, è l'incapacità della mente umana di comprendere le codifiche dei caratteri. Viviamo in una placida isola dell'ignoranza in mezzo a mari neri di codice, e non intendevamo viaggiare lontano. Le lingue, ognuna tesa nella sua stessa direzione, ci hanno finora danneggiato poco; ma un giorno il mettere insieme i piani Unicode dissociati aprirà così terrificanti eccentricità del linguaggio, e della nostra terrificante posizione in esso, che dovremo o separarci dalla rivelazione o fuggire dalla luce nella pace e nella sicurezza di EBCDIC.

    
risposta data 18.12.2013 - 12:59
fonte
2

L'escaping dovrebbe essere compatibile con il set di caratteri, altrimenti la logica di escape può essere ingannata nell'accettare caratteri illegali. Per dimostrarlo, è possibile utilizzare / abusare di caratteri multibyte in una logica di escape ignora del charset.

$user_input = "0xC8 ' EVIL_SQL--";
$variable = mysqli_real_escape_string($user_input);
$SqlQuery = "SELECT something FROM some_table WHERE one_thing = '$variable'";

Tenendo presente che il backslash è codificato come 0x5C (un byte), la nostra logica di escape proverà a sfuggire a quella quota singola prima di EVIL_SQL , quindi ciò che accadrà è che avremo un byte 0xC8 seguito da 0x5C , che sono due byte rappresentati come 0xC85C , che è un carattere a più byte valido (non ho idea di cosa sia).

Il 0xC8 e il backslash sono stati uniti per creare un nuovo personaggio bambino. In altre parole, il backslash è sparito e non può più sfuggire il nostro ' . Quindi il prodotto finale è "SOME_VALID_CHARACTER ' EVIL_SQL" e la query SQL finale diventa

"SELECT something FROM some_table WHERE one_thing = 'SOME_VALID_CHARACTER ' EVIL_SQL--'"

Se la nostra fuga fosse resa nota della codifica accettata sul server, alcune misure possono essere prese per combattere tali attacchi.

Maggiori informazioni: annuncio MySQL sul problema dell'SQL multibyte iniezione e la correzione

    
risposta data 18.12.2013 - 13:12
fonte

Leggi altre domande sui tag