Zapobieganie iniekcji SQL w Node.js.

87

Czy można zapobiec iniekcjom SQL w Node.js (najlepiej za pomocą modułu) w taki sam sposób, w jaki PHP miał przygotowane instrukcje, które chroniły przed nimi.

Jeśli tak to jak? Jeśli nie, to jakie przykłady mogą ominąć podany przeze mnie kod (patrz poniżej).


Jakiś kontekst:

Tworzę aplikację internetową ze stosem zaplecza składającym się z Node.js + MySql przy użyciu modułu node-mysql . Z punktu widzenia użyteczności moduł jest świetny, ale nie zaimplementował jeszcze czegoś podobnego do gotowych instrukcji PHP (chociaż wiem, że jest to w todo ).

Z mojego zrozumienia wynika, że ​​implementacja w PHP gotowych instrukcji, między innymi, bardzo pomogła w zapobieganiu wstrzyknięciom SQL. Martwię się jednak, że moja aplikacja node.js może być podatna na podobne ataki, nawet jeśli domyślnie wprowadzono znaki ucieczki (jak we fragmencie kodu poniżej).

node-mysql wydaje się być najpopularniejszym łącznikiem mysql dla node.js, więc zastanawiałem się, co inne osoby mogą robić (jeśli cokolwiek), aby rozwiązać ten problem - lub czy jest to nawet problem z node.js na początek (nie jestem pewien, jak by to nie wyglądało, ponieważ w grę wchodzą dane wejściowe po stronie użytkownika / klienta).

Czy powinienem na razie przełączyć się na node-mysql-native , skoro zapewnia on przygotowane instrukcje? Waham się, czy to zrobić, ponieważ nie wydaje się być tak aktywny jak node-mysql (choć może to po prostu oznaczać, że jest kompletny).

Oto fragment kodu rejestracji użytkownika, który używa modułu sanitizer , wraz z przygotowaną składnią podobną do instrukcji node-mysql (która, jak wspomniałem powyżej, wykonuje znaki ucieczki), aby zapobiec odpowiednio skryptom krzyżowym i wstrzyknięciom 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?
   });
funseiki
źródło

Odpowiedzi:

60

node-mysqlBiblioteka automatycznie wykonuje ucieczki stosowany jako już robisz. Zobacz https://github.com/felixge/node-mysql#escaping-query-values

Michael Pratt
źródło
3
Jak wspomniałem w moim poście, zdaję sobie sprawę, że biblioteka ucieka ze znaków, ale bardziej martwię się o konsekwencje dla bezpieczeństwa, jeśli nie przełączę się na bibliotekę, która zaimplementowała przygotowane instrukcje, tj. Czy jest zastrzyk SQL, który może wystąpić z tym, co Aktualnie robię?
funseiki
2
Unikanie znaków zapobiega iniekcji SQL. Wstrzyknięcia występują, gdy znaki nie są chronione, a złośliwi użytkownicy mogą to wykorzystać, aby zamknąć zapytanie i rozpocząć nowe, na przykład upuścić tabelę lub wstawić fałszywy rekord. W przypadku znaków ucieczki nie jest to możliwe. Wikipedia zawiera dodatkowe informacje na temat SQL Injection.
Michael Pratt
4
Ale czy zapobiega wszystkim wstrzyknięciom SQL? Ta odpowiedź sugeruje, że nie (przynajmniej dla PHP + MySQL) i sugeruje, że przygotowane instrukcje PHP tak robią. Ponownie, dzieje się to w kontekście PHP.
funseiki
1
Według twojego linku to działa tylko na nieaktualnych wersjach MySQL. Nie wiem, czy ten konkretny atak działa na Node, ale wygląda na to, że miał związek z bardzo określonymi lukami w zabezpieczeniach PHP, więc moje przeczucie brzmi: nie. Nie mówię, że w node-mysql nie ma absolutnie żadnych luk, ale jest już używany w wielu środowiskach produkcyjnych. Jeśli nadal martwisz się o wstrzyknięcie SQL, proponuję ugryźć kulę i wypróbować coś takiego jak MongoDB - nie możesz wykonać wstrzyknięcia SQL, jeśli nie używasz SQL.
Michael Pratt
1
Wyglądało na to, że trasa MongoDB jest dobrym punktem - chociaż obecny projekt dobrze pasowałby do schematu relacyjnego. Poczekam, aby zobaczyć, czy ktoś inny ma wgląd w luki w zabezpieczeniach - w przeciwnym razie wydaje się, że konsensus dotyczy po prostu trzymania się node-mysql
funseiki
12

Biblioteka zawiera sekcję w pliku Readme o ucieczce. Jest natywny dla Javascript, więc nie sugeruję przełączania się na node-mysql-native . Dokumentacja zawiera wskazówki dotyczące ucieczki:

Edycja: node-mysql-native jest również rozwiązaniem opartym wyłącznie na Javascript.

  • Liczby pozostają nietknięte
  • Booleany są konwertowane na true/ falsestrings
  • Obiekty Date są konwertowane na YYYY-mm-dd HH:ii:ssciągi
  • Bufory są konwertowane na ciągi szesnastkowe, np X'0fa5'
  • Ciągi są bezpiecznie uciekane
  • Tablice zamieniane są w listę, np. ['a', 'b']Zamienia się w'a', 'b'
  • Tablice zagnieżdżone są przekształcane w listy zgrupowane (dla wstawiania zbiorczego), np. [['a', 'b'], ['c', 'd']]Zamienia się w('a', 'b'), ('c', 'd')
  • Obiekty są zamieniane w key = 'val'pary. Zagnieżdżone obiekty są rzutowane na ciągi.
  • undefined/ nullsą konwertowane naNULL
  • NaN/ Infinitysą pozostawione bez zmian. MySQL ich nie obsługuje, a próba wstawienia ich jako wartości spowoduje błędy MySQL, dopóki nie zaimplementują obsługi.

Dzięki temu możesz robić takie rzeczy:

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

Tak dobrze jak to:

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

Oprócz tych funkcji możesz również użyć funkcji ucieczki:

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

Aby uniknąć identyfikatorów zapytań:

mysql.escapeId(identifier);

A w odpowiedzi na Twój komentarz do przygotowanych wypowiedzi:

Z punktu widzenia użyteczności moduł jest świetny, ale nie zaimplementował jeszcze czegoś podobnego do przygotowanych instrukcji PHP.

Przygotowane instrukcje znajdują się na liście rzeczy do zrobienia dla tego konektora, ale ten moduł pozwala przynajmniej na określenie niestandardowych formatów, które mogą być bardzo podobne do przygotowanych instrukcji. Oto przykład z pliku 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));
};

Spowoduje to zmianę formatu zapytania połączenia, dzięki czemu możesz używać takich zapytań:

connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
//equivalent to
connection.query("UPDATE posts SET title = " + mysql.escape("Hello MySQL");
heksacyjanek
źródło
Dziękuję za odpowiedź - mam świadomość przygotowanego stylu. Jednak pod spodem bohaterowie uciekają. Zobacz: „Jednak tak naprawdę po prostu używa tego samego connection.escape ()” . O ile nie używam node-mysql-native: z tym właśnie się zmagam. Jeśli node-mysql-native implementuje przygotowane instrukcje, a jego implementacje zapobiegają wstrzyknięciom SQL, czy nie powinienem przełączać się, dopóki node-mysql nie będzie ich miał?
funseiki
To rodzaj pytania na temat jajka i kury. Nie rozwijam aktywnie swojego sterownika, ponieważ większość ludzi używa @ felixge. Prawdopodobnie spróbuję znaleźć trochę czasu na przeniesienie przygotowanych instrukcji do node-mysql, ponieważ rzeczywiście daje to pewne korzyści z wydajności (i potencjalnie utrudnia wstrzykiwanie sql). Zapraszam do komentowania / publikowania problemów, jeśli zdecydujesz się spróbować
Andrey Sidorov
1
@funseiki Jestem pewien, że przygotowane instrukcje byłyby najlepszym rozwiązaniem, ale jestem pewien, że ucieczka zapobiegnie iniekcjom SQL. Ponieważ sam moduł jest obsługiwany przez Joyent, jest on aktywny i ewidentnie dokładnie sprawdzony. Gdyby ten moduł nie był gotowy do produkcji, to nie sądzę, by w zeszłym miesiącu miał średnio 1000 pobrań dziennie. Zauważ, że node-mysql-native minęło 6 miesięcy od ostatniego opracowania, a node-mysql jest bardzo aktywny i pracuje nad nim wiele osób.
heksacyjanid
@AndreySidorov Dziękuję za komentarz - jeśli spróbuję się tym zająć, opublikuję aktualizację. Nie sądzę jednak, żeby to nastąpiło w najbliższym czasie, ponieważ nie wydaje się, że będzie to łatwe do opanowania (będzie to wymagało więcej badań niż obecnie mam czasu). Dziękuję również za stworzenie tego sterownika - jesteście powodem, dla którego Node.js ułatwia szybkie uruchamianie aplikacji
funseiki
@hexacyanide Ponieważ node-mysql jest tak popularny, miałem nadzieję, że uda mi się uzyskać odpowiedź od członków społeczności na temat problemów bezpieczeństwa, które mogli napotkać (lub którym zapobiegli), a także przekonujący argument, dlaczego obecne podejście ucieczki znaków jest bezpieczne wystarczy dla ich kodu.
funseiki
12

Zdaję sobie sprawę, że to starszy post, ale wygląda na to, że odpowiedź nigdy nie została zaznaczona, więc wyrzucę ją tam.

Jeśli chodzi o testowanie, czy moduł, którego używasz, jest bezpieczny, czy nie, istnieje kilka ścieżek, które możesz wybrać. Opowiem o zaletach / wadach każdego z nich, abyś mógł podjąć bardziej świadomą decyzję.

Obecnie nie ma żadnych luk w zabezpieczeniach modułu, którego używasz, jednak często może to prowadzić do fałszywego poczucia bezpieczeństwa, ponieważ bardzo dobrze może istnieć luka w zabezpieczeniach aktualnie wykorzystująca moduł / pakiet oprogramowania, z którego korzystasz i nie zostaniesz ostrzeżony do problemu, dopóki dostawca nie zastosuje poprawki / poprawki.

  1. Aby być na bieżąco z lukami w zabezpieczeniach, będziesz musiał śledzić listy mailingowe, fora, IRC i inne dyskusje dotyczące hakowania. PRO: Często zdarza się, że zdasz sobie sprawę z potencjalnych problemów w bibliotece, zanim sprzedawca zostanie ostrzeżony lub wyda poprawkę / łatkę, aby zaradzić potencjalnej drodze ataku na jego oprogramowanie. CON: Może to być bardzo czasochłonne i wymagające dużych zasobów. Jeśli wybierzesz tę trasę, bot za pomocą kanałów RSS, analizowania dzienników (dzienniki czatu IRC) i / lub narzędzia internetowego używającego fraz kluczowych (w tym przypadku node-mysql-native) i powiadomienia mogą pomóc skrócić czas spędzony na trollowaniu tych zasobów.

  2. Utwórz fuzzer, użyj fuzzera lub innej struktury luk w zabezpieczeniach, takiej jak metasploit , sqlMap itp., Aby pomóc w testowaniu problemów, których sprzedawca mógł nie szukać. PRO: To może okazać się niezawodną metodą przeciwpożarową zapewniającą do akceptowalnego poziomu, czy moduł / oprogramowanie, które wdrażasz, są bezpieczne dla publicznego dostępu. CON: To również staje się czasochłonne i kosztowne. Drugi problem będzie wynikał z fałszywych trafień, a także z niewykształconego przeglądu wyników, w przypadku których występuje problem, ale nie został zauważony.

Naprawdę bezpieczeństwo i ogólnie bezpieczeństwo aplikacji może być bardzo czasochłonne i wymagające dużej ilości zasobów. Menadżerowie zawsze będą używać wzoru do określania opłacalności (siły roboczej, zasobów, czasu, wynagrodzenia itp.) Realizacji dwóch powyższych opcji.

W każdym razie zdaję sobie sprawę, że nie jest to odpowiedź „tak” lub „nie”, na którą można było mieć nadzieję, ale nie sądzę, aby ktokolwiek mógł ci jej udzielić, dopóki nie przeprowadzi analizy danego oprogramowania.

jas-
źródło
3

Wiem, że to pytanie jest stare, ale dla każdego zainteresowanego Mysql-native jest przestarzały, więc stał się MySQL2 , czyli nowym modułem stworzonym z pomocą zespołu oryginalnego modułu MySQL. Ten moduł ma więcej funkcji i myślę, że ma to, czego chcesz, ponieważ przygotował instrukcje (używając.execute ()) jak w PHP dla większego bezpieczeństwa.

Jest również bardzo aktywny (ostatnia zmiana była od 2-1 dni) Nie próbowałem tego wcześniej, ale myślę, że tego chcesz i więcej.

Boy pro
źródło
-1

Najłatwiej jest obsłużyć wszystkie interakcje z bazą danych we własnym module, który można wyeksportować do swoich tras. Jeśli twoja trasa nie ma kontekstu bazy danych, SQL i tak nie może jej dotknąć.

Bird Dad
źródło
To tak naprawdę nie odpowiada na pytanie OP, jak odkażać.
Christopher