web-dev-qa-db-fra.com

Prévention de l'injection SQL dans Node.js

Est-il possible d'empêcher les injections SQL dans Node.js (de préférence avec un module) de la même manière que PHP avait des instructions préparées qui les protégeaient.

Si c'est le cas, comment? Sinon, quels sont quelques exemples qui pourraient contourner le code que j'ai fourni (voir ci-dessous).


Un peu de contexte:

Je crée une application Web avec une pile principale composée de Node.js + MySql à l'aide du module node-mysql . Du point de vue de la convivialité, le module est excellent, mais il n’a pas encore implémenté quelque chose de similaire à Prepared Statements de PHP (bien que je sache qu’il s’agit du todo ).

D'après ce que j'ai compris, la mise en œuvre par PHP des instructions préparées, entre autres, a grandement aidé à prévenir les injections SQL. Je crains cependant que mon application node.js ne soit ouverte à des attaques similaires, même avec la chaîne d'échappement fournie par défaut (comme dans l'extrait de code ci-dessous).

node-mysql semble être le connecteur mysql le plus populaire pour node.js, alors je me demandais ce que les autres personnes pourraient faire (le cas échéant) pour expliquer ce problème - ou s'il s'agit même d'un problème avec node.js (je ne sais pas comment cela ne serait pas, car une entrée côté utilisateur/client est impliquée).

Devrais-je passer à node-mysql-native pour le moment, car il fournit des instructions préparées? J'hésite à le faire, car cela ne semble pas être aussi actif que node-mysql (bien que cela puisse vouloir dire que c'est complet).

Voici un extrait du code d'enregistrement de l'utilisateur, qui utilise le module sanitizer , ainsi que la syntaxe préparée semblable à une instruction de node-mysql (qui, comme je l'ai mentionné plus haut, échappe à des caractères), pour empêcher les scripts intersites et les injections SQL. , respectivement:

// 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?
   });
73
funseiki

La bibliothèque node-mysql effectue automatiquement l'échappement lorsqu'elle est utilisée comme vous le faites déjà. Voir https://github.com/felixge/node-mysql#escaping-query-values ​​

48
Michael Pratt

Je me rends compte que c’est un article plus ancien, mais il semble qu’une réponse n’a jamais été signalée. Je vais donc vous en parler.

En ce qui concerne le fait de vérifier si un module que vous utilisez est sécurisé ou non, vous pouvez emprunter plusieurs itinéraires. Je vais aborder les avantages/inconvénients de chacun afin que vous puissiez prendre une décision plus éclairée.

Actuellement, il n'y a pas de vulnérabilités pour le module que vous utilisez, cependant, cela peut souvent conduire à un faux sentiment de sécurité car il pourrait très bien y avoir une vulnérabilité exploitant actuellement le module/logiciel que vous utilisez et vous ne seriez pas alerté à un problème jusqu'à ce que le fournisseur applique un correctif/correctif.

  1. Pour vous tenir au courant des vulnérabilités, vous devrez suivre des listes de diffusion, des forums, IRC et d’autres discussions relatives au piratage informatique . PRO: Vous pourrez souvent vous rendre compte des problèmes potentiels au sein d’une bibliothèque avant que le fournisseur alerté ou a publié un correctif/correctif pour remédier à la voie d’attaque potentielle de leur logiciel ..__CON: cela peut prendre beaucoup de temps et prendre beaucoup de ressources. Si vous suivez cet itinéraire, un bot utilisant des flux RSS, l'analyse des journaux (journaux de discussion IRC) et/ou un scrapper Web utilisant des phrases clés (dans ce cas, node-mysql-native) et les notifications peuvent aider à réduire le temps passé à parcourir ces ressources.

  2. Créez un fuzzer, utilisez un fuzzer ou un autre cadre de vulnérabilité tel que metasploit , sqlMap etc. pour vous aider à tester les problèmes que le fournisseur n'a peut-être pas recherchés . PRO: Ceci peut s’avérer un moyen sûr d’assurer à un niveau acceptable si le module/logiciel que vous implémentez est sécurisé (e) pour un accès public accessible au public ..__CON: Cela prend également du temps et coûte cher. L'autre problème proviendra de faux positifs ainsi que d'un examen non éclairé des résultats où un problème réside mais n'est pas remarqué.

En réalité, la sécurité des applications et la sécurité des applications peuvent prendre beaucoup de temps et de ressources. Les gestionnaires utiliseront toujours une formule pour déterminer le rapport coût/efficacité (ressources humaines, ressources, temps, rémunération, etc.) permettant d’exécuter les deux options ci-dessus.

Quoi qu'il en soit, je réalise que ce n'est pas une réponse «oui» ou «non» que l'on aurait pu espérer, mais je ne pense pas que quiconque puisse vous donner cette information avant d'avoir analysé le logiciel en question.

9
jas-

La bibliothèque a un section dans le fichier Readme sur le fait de s'échapper. Il s'agit d'un script Javascript natif. Je ne suggère donc pas de passer à node-mysql-native . La documentation indique ces directives pour échapper:

Edit: _ ​​ node-mysql-native est aussi une solution purement Javascript.

  • Les chiffres sont laissés intacts
  • Les booléens sont convertis en chaînes true/false
  • Les objets de date sont convertis en chaînes YYYY-mm-dd HH:ii:ss
  • Les tampons sont convertis en chaînes hexadécimales, par ex. X'0fa5'
  • Les ficelles sont échappées en toute sécurité
  • Les tableaux sont transformés en liste, par exemple ['a', 'b'] se transforme en 'a', 'b'
  • Les tableaux imbriqués sont transformés en listes groupées (pour les insertions en bloc), par ex. [['a', 'b'], ['c', 'd']] se transforme en ('a', 'b'), ('c', 'd')
  • Les objets sont transformés en paires key = 'val'. Les objets imbriqués sont convertis en chaînes.
  • undefined/null sont convertis en NULL
  • NaN/Infinity sont laissés tels quels. MySQL ne les supporte pas, et essayer de les insérer en tant que valeurs déclenchera des erreurs MySQL jusqu'à ce qu'ils implémentent le support.

Cela vous permet de faire des choses comme ceci:

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'
});

Ainsi que cette:

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'
});

Outre ces fonctions, vous pouvez également utiliser les fonctions d'échappement:

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

Pour échapper aux identificateurs de requête:

mysql.escapeId(identifier);

Et en réponse à votre commentaire sur les déclarations préparées:

Du point de vue de la convivialité, le module est excellent, mais il n’a pas encore implémenté quelque chose de similaire aux déclarations préparées de PHP.

Les instructions préparées figurent sur la liste todo de ce connecteur, mais ce module vous permet au moins de spécifier des formats personnalisés qui peuvent être très similaires aux instructions préparées. Voici un exemple tiré du 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));
};

Cela change le format de requête de la connexion afin que vous puissiez utiliser des requêtes comme celle-ci:

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

Je sais que cette question est ancienne, mais pour tous les intéressés, Mysql-native est obsolète et est devenu MySQL2 qui est un nouveau module créé avec l'aide de l'équipe du module MySQL d'origine. Ce module a plus de fonctionnalités et je pense qu’il a ce que vous voulez car il a préparé des instructions (en utilisant.execute ()) comme dans PHP pour plus de sécurité. 

C'est aussi très actif (le dernier changement remonte à 2-1 jours). Je ne l'avais pas essayé auparavant mais je pense que c'est ce que vous voulez et plus encore.

1
Boy pro

Le moyen le plus simple consiste à gérer toutes les interactions de votre base de données dans son propre module, que vous exportez vers vos itinéraires. Si votre route n'a pas de contexte dans la base de données, SQL ne peut quand même pas y toucher.

0
Bird Dad