Prevenire l'iniezione SQL in Node.js


88

È possibile impedire le iniezioni SQL in Node.js (preferibilmente con un modulo) nello stesso modo in cui PHP aveva istruzioni preparate che le proteggevano.

Se é cosi, come? In caso contrario, quali sono alcuni esempi che potrebbero aggirare il codice che ho fornito (vedi sotto).


Alcuni contesti:

Sto realizzando un'applicazione web con uno stack back-end costituito da Node.js + MySql utilizzando il modulo node-mysql . Dal punto di vista dell'usabilità, il modulo è grande, ma non ha ancora attuato qualcosa di simile al PHP prepared statement (anche se sono consapevoli che è sul todo ).

Dalla mia comprensione, l'implementazione di istruzioni preparate da parte di PHP, tra le altre cose, ha aiutato molto nella prevenzione delle SQL injection. Sono preoccupato, tuttavia, che la mia app node.js possa essere aperta ad attacchi simili, anche con l'escape della stringa fornito per impostazione predefinita (come nello snippet di codice di seguito).

node-mysql sembra essere il connettore mysql più popolare per node.js, quindi mi chiedevo cosa potrebbero fare gli altri (semmai) per tenere conto di questo problema - o se è anche un problema con node.js per cominciare (non sono sicuro di come ciò non sarebbe, poiché è coinvolto l'input lato utente / client).

Devo passare a node-mysql-native per il momento, poiché fornisce istruzioni preparate? Sono riluttante a farlo, perché non sembra essere attivo come node-mysql (anche se ciò potrebbe significare solo che è completo).

Ecco uno snippet del codice di registrazione dell'utente, che utilizza il modulo sanitizer , insieme alla sintassi simile a un'istruzione preparata da node-mysql (che, come accennato in precedenza, esegue l'escape dei caratteri), per prevenire rispettivamente lo scripting cross site e le iniezioni sql:

// Prevent xss
var clean_user = sanitizer.sanitize(username);

// assume password is hashed already
var post = {Username: clean_user, Password: hash};

// This just uses connection.escape() underneath
var query = connection.query('INSERT INTO users SET ?', post,
   function(err, results)
   {
       // Can a Sql injection happen here?
   });

Risposte:


60

La node-mysqllibreria esegue automaticamente l'escape quando viene utilizzata come stai già facendo. Vedi https://github.com/felixge/node-mysql#escaping-query-values


3
Come accennato nel mio post, sono consapevole del fatto che la libreria sfugge ai caratteri, ma sono più preoccupato per le implicazioni sulla sicurezza se non passo a una libreria che ha implementato istruzioni preparate, ovvero c'è un'iniezione SQL che può verificarsi con cosa Che sto facendo attualmente?
funseiki

2
L'escape dei caratteri impedisce l'iniezione SQL. Le iniezioni si verificano quando i caratteri non vengono sottoposti a escape e gli utenti malintenzionati possono sfruttarlo per chiudere la query e avviarne una nuova per, ad esempio, eliminare una tabella o inserire un record falso. Con caratteri di escape, questo non è possibile. Wikipedia ha alcune informazioni aggiuntive su SQL Injection.
Michael Pratt

4
Ma impedisce tutte le iniezioni SQL? Questa risposta suggerisce di no (almeno per PHP + MySQL) e implica che le istruzioni preparate di PHP lo facciano. Di nuovo, questo è nel contesto di PHP.
funseiki

1
Secondo il tuo link, funziona solo su versioni obsolete di MySQL. Non so se quel particolare attacco funzioni su Node, ma sembra che abbia a che fare con vulnerabilità PHP molto specifiche, quindi la mia sensazione istintiva è no. Non sto dicendo che non ci siano assolutamente vulnerabilità in node-mysql, ma viene già utilizzato in una grande quantità di ambienti di produzione. Se sei ancora preoccupato per l'iniezione SQL, ti suggerisco di mordere il proiettile e provare qualcosa come MongoDB: non puoi eseguire un'iniezione SQL se non stai usando SQL.
Michael Pratt

1
Sembrava così e il percorso di MongoDB è un buon punto, anche se il design attuale si presterebbe bene a uno schema relazionale. Aspetterò di vedere se qualcun altro ha informazioni sulle vulnerabilità della sicurezza - altrimenti, sembra che il consenso sia solo per
restare

12

La libreria ha una sezione nel file readme sull'escape. È Javascript-native, quindi non suggerisco di passare a node-mysql-native . La documentazione afferma queste linee guida per l'escape:

Modifica: node-mysql-native è anche una soluzione JavaScript puro.

  • I numeri rimangono intatti
  • I booleani vengono convertiti in true/ falsestrings
  • Gli oggetti data vengono convertiti in YYYY-mm-dd HH:ii:ssstringhe
  • I buffer vengono convertiti in stringhe esadecimali, ad es X'0fa5'
  • Le stringhe vengono salvate in modo sicuro
  • Gli array vengono trasformati in elenco, ad esempio ['a', 'b']si trasforma in'a', 'b'
  • Gli array annidati vengono trasformati in elenchi raggruppati (per inserimenti in blocco), ad esempio [['a', 'b'], ['c', 'd']]si trasforma in('a', 'b'), ('c', 'd')
  • Gli oggetti vengono trasformati in key = 'val'coppie. Gli oggetti nidificati vengono convertiti in stringhe.
  • undefined / null vengono convertiti inNULL
  • NaN / Infinity Sono lasciati così come sono. MySQL non li supporta e il tentativo di inserirli come valori attiverà errori MySQL fino a quando non implementeranno il supporto.

Ciò ti consente di fare cose in questo modo:

var userId = 5;
var query = connection.query('SELECT * FROM users WHERE id = ?', [userId], function(err, results) {
  //query.sql returns SELECT * FROM users WHERE id = '5'
});

Oltre a questo:

var post  = {id: 1, title: 'Hello MySQL'};
var query = connection.query('INSERT INTO posts SET ?', post, function(err, result) {
  //query.sql returns INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
});

Oltre a queste funzioni, puoi anche utilizzare le funzioni di escape:

connection.escape(query);
mysql.escape(query);

Per sfuggire agli identificatori di query:

mysql.escapeId(identifier);

E in risposta al tuo commento sulle dichiarazioni preparate:

Dal punto di vista dell'usabilità, il modulo è fantastico, ma non ha ancora implementato qualcosa di simile alle istruzioni preparate di PHP.

Le istruzioni preparate sono sulla todo list per questo connettore, ma questo modulo, almeno consente di specificare formati personalizzati che possono essere molto simile a istruzioni preparate. Ecco un esempio dal file readme:

connection.config.queryFormat = function (query, values) {
  if (!values) return query;
  return query.replace(/\:(\w+)/g, function (txt, key) {
    if (values.hasOwnProperty(key)) {
      return this.escape(values[key]);
    }
    return txt;
  }.bind(this));
};

Questo cambia il formato della query della connessione in modo da poter utilizzare query come questa:

connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
//equivalent to
connection.query("UPDATE posts SET title = " + mysql.escape("Hello MySQL");

Grazie per la risposta - Sono consapevole dello stile simile a quello preparato. Sotto, però, i personaggi vengono scappati. Vedere: "Tuttavia, in realtà utilizza solo la stessa connection.escape ()" . Per quanto riguarda il non utilizzo di node-mysql-native: questo è ciò con cui sto lottando. Se node-mysql-native implementa le istruzioni preparate e le sue implementazioni prevengono le iniezioni SQL, non dovrei fare il passaggio fino a quando node-mysql non le ha?
funseiki

È una specie di domanda di pollo e uova. Non sto sviluppando attivamente il mio driver perché la maggior parte delle persone usa @ felixge.Probabilmente cercherò di trovare un po 'di tempo per trasferire le istruzioni preparate su node-mysql in quanto offre alcuni vantaggi in termini di prestazioni (e potenzialmente rende più difficili le iniezioni di sql). Sentiti libero di commentare / pubblicare problemi se decidi di
provarlo

1
@funseiki Sono sicuro che le dichiarazioni preparate sarebbero la soluzione migliore, ma sono molto sicuro che l'escape impedirà le iniezioni SQL. Poiché il modulo stesso è supportato da Joyent, il modulo è attivo ed evidentemente controllato accuratamente. Se questo modulo non fosse pronto per la produzione, non credo che il mese scorso avrebbe una media di 1000 download al giorno. Nota che node-mysql-native sono trascorsi 6 mesi dall'ultimo sviluppo e node-mysql è molto attivo, con più persone che ci lavorano.
esacianide

@AndreySidorov Grazie per il commento - se tento di affrontarlo, posterò un aggiornamento. Non penso che sarà presto, però, dal momento che non sembra che sarà una bestia facile da gestire (richiederà più ricerche di quante ne abbia attualmente il tempo). Grazie anche per aver creato quel driver - voi ragazzi siete il motivo per cui Node.js rende facile far funzionare rapidamente le app
funseiki

@hexacyanide Poiché node-mysql è così popolare, speravo di poter ottenere una risposta dai membri della comunità in merito ai problemi di sicurezza che potrebbero aver incontrato (o prevenuto), nonché un argomento convincente sul motivo per cui l'attuale approccio di fuga dei caratteri è sicuro abbastanza per il loro codice.
funseiki

12

Mi rendo conto che questo è un post più vecchio ma sembra che una risposta non sia mai stata contrassegnata, quindi lo butto là fuori.

Per quanto riguarda il test se un modulo che stai utilizzando è sicuro o meno, ci sono diversi percorsi che puoi prendere. Tratterò i pro / contro di ciascuno in modo da poter prendere una decisione più informata.

Attualmente non ci sono vulnerabilità per il modulo che stai utilizzando, tuttavia, questo può spesso portare a un falso senso di sicurezza in quanto potrebbe esserci una vulnerabilità che attualmente sfrutta il modulo / pacchetto software che stai utilizzando e non verrai avvisato a un problema fino a quando il fornitore non applica una correzione / patch.

  1. Per tenere il passo con le vulnerabilità dovrai seguire mailing list, forum, IRC e altre discussioni relative all'hacking. PRO: spesso è possibile che ci si accorga di potenziali problemi all'interno di una libreria prima che un fornitore sia stato avvisato o abbia emesso una correzione / patch per porre rimedio alla potenziale via di attacco al proprio software. CONTRO: Questo può richiedere molto tempo e molte risorse. Se segui questa strada, un bot che utilizza feed RSS, analisi dei log (registri chat IRC) eo uno scrapper web che utilizza frasi chiave (in questo caso node-mysql-native) e le notifiche possono aiutare a ridurre il tempo impiegato per trollare queste risorse.

  2. Crea un fuzzer, usa un fuzzer o un altro framework di vulnerabilità come metasploit , sqlMap ecc. Per testare i problemi che il fornitore potrebbe non aver cercato. PRO: Questo può rivelarsi un metodo sicuro per garantire a un livello accettabile se il modulo / software che stai implementando è sicuro per l'accesso pubblico. CONTRO: Anche questo diventa lungo e costoso. L'altro problema deriverà da falsi positivi e da una revisione non istruita dei risultati in cui un problema risiede ma non viene notato.

La sicurezza reale e la sicurezza delle applicazioni in generale possono richiedere molto tempo e risorse. Una cosa che i manager useranno sempre è una formula per determinare il rapporto costo-efficacia (manodopera, risorse, tempo, paga ecc.) Di eseguire le due opzioni di cui sopra.

Ad ogni modo, mi rendo conto che questa non è una risposta "sì" o "no" che si sperava, ma non credo che nessuno possa dartela finché non eseguirà un'analisi del software in questione.


3

So che questa domanda è vecchia ma per chiunque sia interessato, Mysql-native è stato obsoleto, quindi è diventato MySQL2 un nuovo modulo creato con l'aiuto del team del modulo MySQL originale. Questo modulo ha più funzionalità e penso che abbia ciò che desideri in quanto ha istruzioni preparate (usando.execute ()) come in PHP per maggiore sicurezza.

È anche molto attivo (l'ultima modifica era da 2-1 giorni) Non l'ho provato prima ma penso che sia quello che vuoi e altro ancora.


-1

Il modo più semplice è gestire tutte le interazioni del database nel suo modulo che esporti alle tue rotte. Se il percorso non ha un contesto del database, SQL non può toccarlo comunque.


Questo non risponde davvero alla domanda di OP su come disinfettare.
Christopher
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.