Verhindern der SQL-Injektion in Node.js.

85

Ist es möglich, SQL-Injektionen in Node.js (vorzugsweise mit einem Modul) auf dieselbe Weise zu verhindern, wie PHP vorbereitete Anweisungen hatte, die gegen sie geschützt waren?

Wenn das so ist, wie? Wenn nicht, welche Beispiele könnten den von mir bereitgestellten Code umgehen (siehe unten).


Einige Zusammenhänge:

Ich mache eine Webanwendung mit einem Back-End-Stack, der aus Node.js + MySql besteht, unter Verwendung des Node-Mysql- Moduls. Unter dem Gesichtspunkt der Benutzerfreundlichkeit ist das Modul großartig, aber es hat noch nichts Ähnliches wie die Prepared Statements von PHP implementiert (obwohl mir bewusst ist, dass es sich um eine Aufgabe handelt ).

Nach meinem Verständnis hat die Implementierung vorbereiteter Anweisungen durch PHP unter anderem wesentlich zur Verhinderung von SQL-Injektionen beigetragen . Ich mache mir jedoch Sorgen, dass meine node.js-App ähnlichen Angriffen ausgesetzt sein könnte, selbst wenn die Zeichenfolge standardmäßig maskiert ist (wie im folgenden Code-Snippet).

node-mysql scheint der beliebteste mysql-Connector für node.js zu sein, daher habe ich mich gefragt, was andere Leute (wenn überhaupt) tun könnten, um dieses Problem zu erklären - oder ob es überhaupt ein Problem mit node.js ist (Ich bin mir nicht sicher, wie das nicht wäre, da benutzer- / clientseitige Eingaben beteiligt sind.)

Sollte ich vorerst zu node-mysql-native wechseln , da es vorbereitete Anweisungen enthält? Ich zögere, dies zu tun, da es nicht so aktiv zu sein scheint wie Node-MySQL (obwohl dies nur bedeuten kann, dass es vollständig ist).

Hier ist ein Ausschnitt aus dem Benutzerregistrierungscode, der das Desinfektionsmodul zusammen mit der vorbereiteten anweisungsähnlichen Syntax von node-mysql verwendet (die, wie oben erwähnt, das Entweichen von Zeichen bewirkt), um Cross-Site-Scripting bzw. SQL-Injektionen zu verhindern:

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

Antworten:

58

Die node-mysqlBibliothek führt automatisch ein Escapezeichen durch, wenn sie wie bereits verwendet verwendet wird. Siehe https://github.com/felixge/node-mysql#escaping-query-values

Michael Pratt
quelle
3
Wie in meinem Beitrag erwähnt, ist mir bewusst, dass die Bibliothek Zeichen entgeht, aber ich mache mir mehr Sorgen über die Auswirkungen auf die Sicherheit, wenn ich nicht zu einer Bibliothek wechsle, die vorbereitete Anweisungen implementiert hat, dh gibt es eine SQL-Injection, die mit was auftreten kann Ich mache gerade?
funseiki
2
Das Escaping von Zeichen verhindert die SQL-Injection. Injektionen treten auf, wenn Zeichen nicht maskiert werden, und böswillige Benutzer können dies ausnutzen, um die Abfrage zu schließen und eine neue zu starten, um beispielsweise eine Tabelle zu löschen oder einen gefälschten Datensatz einzufügen. Bei maskierten Zeichen ist dies nicht möglich. Wikipedia bietet einige zusätzliche Informationen zu SQL Injection.
Michael Pratt
4
Aber verhindert es alle SQL-Injektionen? Diese Antwort schlägt nicht vor (zumindest für PHP + MySQL) und impliziert, dass die vorbereiteten Anweisungen von PHP dies tun. Auch dies steht im Zusammenhang mit PHP.
funseiki
1
Laut Ihrem Link funktioniert dies nur bei veralteten Versionen von MySQL. Ich weiß nicht, ob dieser bestimmte Angriff auf Node funktioniert, aber es sieht so aus, als hätte er mit sehr spezifischen PHP-Schwachstellen zu tun, also ist mein Bauchgefühl nein. Ich sage nicht, dass es absolut keine Schwachstellen in Node-MySQL gibt, aber es wird bereits in vielen Produktionsumgebungen verwendet. Wenn Sie sich immer noch Sorgen um die SQL-Injection machen, würde ich vorschlagen, die Kugel zu beißen und etwas wie MongoDB auszuprobieren - kann keine SQL-Injection durchführen, wenn Sie kein SQL verwenden.
Michael Pratt
1
Es sah so aus und die MongoDB-Route ist ein guter Punkt - obwohl sich das aktuelle Design gut für ein relationales Schema eignet. Ich werde abwarten, ob jemand anderes Einblick in die Sicherheitslücken hat - ansonsten scheint der Konsens darin zu bestehen, nur bei Node-
MySQL zu bleiben
12

Die Bibliothek hat einen Abschnitt in der Readme-Datei über das Entkommen. Es ist Javascript-native, daher empfehle ich nicht, zu Node-MySQL-native zu wechseln . In der Dokumentation sind folgende Richtlinien für die Flucht aufgeführt:

Bearbeiten: node-mysql-native ist auch eine reine Javascript-Lösung.

  • Zahlen bleiben unberührt
  • Boolesche Werte werden in true/ falsestrings konvertiert
  • Datumsobjekte werden in YYYY-mm-dd HH:ii:ssZeichenfolgen konvertiert
  • Puffer werden in hexadezimale Zeichenfolgen konvertiert, z X'0fa5'
  • Saiten sind sicher entkommen
  • Arrays werden in Listen umgewandelt, z. B. ['a', 'b']in'a', 'b'
  • Verschachtelte Arrays werden in gruppierte Listen umgewandelt (für Masseneinfügungen), z. B. [['a', 'b'], ['c', 'd']]in('a', 'b'), ('c', 'd')
  • Objekte werden zu key = 'val'Paaren. Verschachtelte Objekte werden in Zeichenfolgen umgewandelt.
  • undefinedIch werde nullkonvertiert zuNULL
  • NaNIch werde wie Infinityes ist belassen. MySQL unterstützt diese nicht und der Versuch, sie als Werte einzufügen, löst MySQL-Fehler aus, bis sie die Unterstützung implementieren.

Auf diese Weise können Sie Folgendes tun:

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

So gut wie das:

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

Neben diesen Funktionen können Sie auch die Escape-Funktionen verwenden:

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

So entgehen Sie Abfragekennungen:

mysql.escapeId(identifier);

Und als Antwort auf Ihren Kommentar zu vorbereiteten Aussagen:

Aus Sicht der Benutzerfreundlichkeit ist das Modul großartig, aber es hat noch nichts Ähnliches wie die Prepared Statements von PHP implementiert.

Die vorbereiteten Anweisungen befinden sich in der Aufgabenliste für diesen Connector, aber in diesem Modul können Sie zumindest benutzerdefinierte Formate angeben, die vorbereiteten Anweisungen sehr ähnlich sein können. Hier ist ein Beispiel aus der Readme-Datei:

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

Dadurch wird das Abfrageformat der Verbindung geändert, sodass Sie folgende Abfragen verwenden können:

connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
//equivalent to
connection.query("UPDATE posts SET title = " + mysql.escape("Hello MySQL");
Hexacyanid
quelle
Vielen Dank für die Antwort - ich bin mir des vorbereiteten Stils bewusst. Darunter werden die Charaktere jedoch entkommen. Siehe: "Es wird jedoch nur dieselbe Verbindung verwendet. Scape ()" . Soweit ich Node-MySQL-Native nicht benutze: Damit habe ich zu kämpfen. Wenn node-mysql-native vorbereitete Anweisungen implementiert und deren Implementierung SQL-Injektionen verhindert, sollte ich den Wechsel nicht vornehmen, bis node-mysql sie hat?
funseiki
Es ist eine Art Henne-Ei-Frage. Ich entwickle meinen Treiber nicht aktiv, da die meisten Leute @ felixges verwenden. Ich werde wahrscheinlich versuchen, etwas Zeit zu finden, um vorbereitete Anweisungen auf Node-MySQL zu portieren, da dies tatsächlich einige Leistungsvorteile bietet (und möglicherweise SQL-Injektionen erschwert). Fühlen Sie sich frei, Probleme zu kommentieren / zu posten, wenn Sie sich entscheiden, es zu versuchen
Andrey Sidorov
1
@funseiki Ich bin sicher, dass vorbereitete Anweisungen die beste Lösung wären, aber ich bin mir sehr sicher, dass das Escapezeichen SQL-Injektionen verhindert. Da das Modul selbst von Joyent unterstützt wird, ist das Modul aktiv und wird offensichtlich gründlich überprüft. Wenn dieses Modul nicht produktionsbereit wäre, hätte das Modul im letzten Monat wahrscheinlich nicht durchschnittlich 1000 Downloads pro Tag. Beachten Sie, dass Node-MySQL-native 6 Monate seit der letzten Entwicklung vergangen ist und Node-MySQL sehr aktiv ist und mehrere Personen daran arbeiten.
Hexacyanid
@AndreySidorov Danke für den Kommentar - wenn ich versuche, ihn anzugehen, werde ich ein Update veröffentlichen. Ich denke jedoch nicht, dass es bald soweit sein wird, da es nicht so aussieht, als wäre es ein leicht zu handhabendes Tier (es wird mehr Forschung erfordern, als ich derzeit Zeit habe). Vielen Dank auch für die Erstellung dieses Treibers - ihr seid der Grund, warum Node.js es einfach macht, Apps schnell zum Laufen zu bringen
funseiki
@hexacyanide Da Node-MySQL so beliebt ist, hatte ich gehofft, dass ich von Mitgliedern der Community eine Antwort zu Sicherheitsproblemen erhalten kann, auf die sie möglicherweise gestoßen sind (oder die sie verhindert haben), sowie ein überzeugendes Argument dafür, warum der aktuelle Ansatz der Charakterflucht sicher ist genug für ihren Code.
funseiki
12

Mir ist klar, dass dies ein älterer Beitrag ist, aber es scheint, dass eine Antwort nie markiert wurde, also werde ich dies hier rauswerfen.

In Bezug auf das Testen, ob ein von Ihnen verwendetes Modul sicher ist oder nicht, können Sie mehrere Wege einschlagen. Ich werde auf die Vor- und Nachteile jedes einzelnen eingehen, damit Sie eine fundiertere Entscheidung treffen können.

Derzeit gibt es keine Sicherheitslücken für das von Ihnen verwendete Modul. Dies kann jedoch häufig zu einem falschen Sicherheitsgefühl führen, da möglicherweise eine Sicherheitslücke vorliegt, die das von Ihnen verwendete Modul / Softwarepaket ausnutzt, und Sie nicht benachrichtigt werden auf ein Problem, bis der Anbieter einen Fix / Patch anwendet.

  1. Um über Sicherheitslücken auf dem Laufenden zu bleiben, müssen Sie Mailinglisten, Foren, IRC und anderen Diskussionen zum Thema Hacking folgen. PRO: Oft werden Sie auf potenzielle Probleme in einer Bibliothek aufmerksam, bevor ein Anbieter benachrichtigt wurde oder einen Fix / Patch herausgegeben hat, um den potenziellen Angriffsweg auf seine Software zu beheben. CON: Dies kann sehr zeitaufwändig und ressourcenintensiv sein. Wenn Sie diesen Weg gehen, können ein Bot, der RSS-Feeds verwendet, eine Protokollanalyse (IRC-Chat-Protokolle) und ein Web-Scrapper mithilfe von Schlüsselphrasen (in diesem Fall Node-MySQL-Native) und Benachrichtigungen dazu beitragen, den Zeitaufwand für das Durchsuchen dieser Ressourcen zu verringern.

  2. Erstellen Sie einen Fuzzer, verwenden Sie einen Fuzzer oder ein anderes Schwachstellen-Framework wie Metasploit , SQLMap usw., um Probleme zu testen, nach denen der Anbieter möglicherweise nicht gesucht hat. PRO: Dies kann sich als sichere Methode erweisen, um auf einem akzeptablen Niveau sicherzustellen, ob das von Ihnen implementierte Modul / die Software für den öffentlichen Zugriff sicher ist oder nicht. CON: Dies wird auch zeitaufwändig und kostspielig. Das andere Problem ergibt sich aus falsch positiven Ergebnissen sowie einer ungebildeten Überprüfung der Ergebnisse, bei denen ein Problem vorliegt, aber nicht bemerkt wird.

Wirklich Sicherheit und Anwendungssicherheit im Allgemeinen können sehr zeitaufwändig und ressourcenintensiv sein. Eine Sache, die Manager immer verwenden, ist eine Formel, um die Kosteneffizienz (Arbeitskräfte, Ressourcen, Zeit, Bezahlung usw.) der Ausführung der beiden oben genannten Optionen zu bestimmen.

Wie auch immer, mir ist klar, dass dies keine Ja- oder Nein-Antwort ist, auf die man gehofft hat, aber ich glaube, niemand kann Ihnen das geben, bis er eine Analyse der betreffenden Software durchführt.

jas-
quelle
3

Ich weiß, dass diese Frage alt ist, aber für alle Interessierten ist MySQL-native veraltet, so dass es zu MySQL2 wurde , einem neuen Modul, das mit Hilfe des ursprünglichen MySQL- Modulteams erstellt wurde. Dieses Modul hat mehr Funktionen und ich denke, es hat das, was Sie wollen, da es Anweisungen (unter Verwendung von .execute ()) wie in PHP für mehr Sicherheit vorbereitet hat.

Es ist auch sehr aktiv (die letzte Änderung war von 2-1 Tagen). Ich habe es vorher nicht ausprobiert, aber ich denke, es ist das, was Sie wollen und mehr.

Junge Pro
quelle
-1

Am einfachsten ist es, alle Ihre Datenbankinteraktionen in einem eigenen Modul zu verarbeiten, das Sie in Ihre Routen exportieren. Wenn Ihre Route keinen Kontext der Datenbank hat, kann SQL sie sowieso nicht berühren.

Vogel Papa
quelle
Das beantwortet die Frage von OP, wie man saniert, nicht wirklich.
Christopher