Запобігання ін’єкції SQL у Node.js


86

Чи можна запобігти ін'єкціям SQL в Node.js (бажано за допомогою модуля) так само, як PHP підготував заяви, які захищали від них.

Якщо так, то як? Якщо ні, то які приклади можуть обійти код, який я надав (див. Нижче).


Деякий контекст:

Я роблю веб-додаток із внутрішнім стеком, що складається з Node.js + MySql, використовуючи модуль node-mysql . З точки зору юзабіліті, модуль чудовий, але він ще не реалізував щось подібне до підготовлених заяв PHP (хоча я знаю, що це вже зроблено ).

Наскільки я розумію, реалізація PHP підготовлених заяв, серед іншого, значно допомогла у запобіганні ін'єкціям SQL. Однак я переживаю, що моя програма node.js може бути відкрита для подібних атак, навіть якщо рядок вимкнено за замовчуванням (як у фрагменті коду нижче).

node-mysql, здається, є найпопулярнішим з'єднувачем mysql для node.js, тому мені було цікаво, що можуть робити інші люди (якщо взагалі щось), щоб пояснити цю проблему - або якщо це навіть проблема з node.js для початку (не впевнений, як цього не було б, оскільки задіяно введення з боку користувача / клієнта).

Чи слід мені перейти на node-mysql-native , поки він надає підготовлені оператори? Я вагаюся це зробити, тому що це, здається, не настільки активне, як node-mysql (хоча це може просто означати, що воно завершено).

Ось фрагмент коду реєстрації користувача, який використовує модуль дезінфікуючого засобу разом із підготовленим синтаксисом, схожим на node-mysql (який, як я вже згадував вище, робить екранування символів), щоб запобігти міжсайтовим сценаріям та ін'єкціям 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?
   });

Відповіді:


59

node-mysqlБібліотека автоматично виконує рятуючись при використанні , як ви вже робите. Див. Https://github.com/felixge/node-mysql#escaping-query-values


3
Як вже згадувалося в моєму дописі, я знаю, що бібліотека уникає символів, але мене більше турбують наслідки для безпеки, якщо я не перейду до бібліотеки, яка реалізує підготовлені оператори, тобто чи існує ін'єкція SQL, яка може відбуватися з тим, що Я зараз роблю?
funseiki

2
Втеча символів перешкоджає введенню SQL. Ін’єкції відбуваються, коли символи не захищаються, і зловмисні користувачі можуть використати це, щоб закрити запит і розпочати новий, скажімо, опустити таблицю або вставити підроблений запис. Зі втеклими персонажами це неможливо. У Вікіпедії є додаткова інформація про SQL Injection.
Майкл Пратт,

4
Але чи це запобігає всім ін’єкціям SQL? Ця відповідь передбачає, що ні (принаймні для PHP + MySQL), і означає, що підготовлені заяви PHP це роблять. Знову ж таки, це в контексті PHP.
funseiki

1
Відповідно до вашого посилання, це працює лише на застарілих версіях MySQL. Я не знаю, чи працює ця конкретна атака на Node, але, схоже, це було пов’язано з дуже специфічними вразливостями PHP, тому моє відчуття кишки - ні. Я не кажу, що в node-mysql немає абсолютно уразливих місць, але він вже використовується у багатьох виробничих середовищах. Якщо ви все ще турбуєтеся про ін'єкцію SQL, я б запропонував перекусити кулю і спробувати щось на зразок MongoDB - не можна робити ін'єкцію SQL, якщо ви не використовуєте SQL.
Майкл Пратт,

1
Це виглядало так, і маршрут MongoDB - це хороший момент, хоча нинішня конструкція добре підходить для реляційної схеми. Я зачекаю, щоб побачити, чи хтось ще має уявлення про вразливі місця безпеки - інакше, здається, консенсус стосується просто дотримання node-mysql
funseiki

12

У бібліотеці є розділ у readme про втечу. Це Javascript-native, тому я не пропоную переходити на node-mysql-native . Документація містить ці вказівки щодо виходу:

Редагувати: node-mysql-native - це також рішення Javascript.

  • Цифри залишаються недоторканими
  • Логічні перетворюються в true/ falseрядки
  • Об'єкти дати перетворюються на YYYY-mm-dd HH:ii:ssрядки
  • Буфери перетворюються на шістнадцяткові рядки, наприклад X'0fa5'
  • Струни безпечно захищені
  • Масиви перетворюються на список, наприклад, ['a', 'b']перетворюються на'a', 'b'
  • Вкладені масиви перетворюються на згруповані списки (для масових вставок), наприклад, [['a', 'b'], ['c', 'd']]перетворюються на('a', 'b'), ('c', 'd')
  • Предмети перетворюються в key = 'val'пари. Вкладені об'єкти передаються в рядки.
  • undefined/ nullперетворюються наNULL
  • NaN/ Infinityзалишаються як є. MySQL їх не підтримує, і спроба вставити їх як значення спричинить помилки MySQL, поки вони не реалізують підтримку.

Це дозволяє вам робити такі речі:

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

А також це:

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

Окрім цих функцій, ви також можете використовувати функції екранування:

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

Щоб уникнути ідентифікаторів запиту:

mysql.escapeId(identifier);

І як відповідь на ваш коментар до підготовлених заяв:

З точки зору юзабіліті, модуль чудовий, але він ще не реалізував щось подібне до підготовлених заяв PHP.

Підготовлені оператори знаходяться в списку завдань для цього з'єднувача, але цей модуль принаймні дозволяє вказати власні формати, які можуть бути дуже схожими на підготовлені оператори. Ось приклад із 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));
};

Це змінює формат запиту підключення, тому ви можете використовувати такі запити:

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

Дякую за відповідь - я знаю про підготовлений стиль. Однак внизу герої втікають. Дивіться: "Однак він насправді просто використовує один і той же connection.escape ()" . Що стосується не використання node-mysql-native: це те, з чим я борюся. Якщо node-mysql-native реалізує підготовлені оператори, а їх реалізація перешкоджає ін'єкціям SQL, чи не слід робити перемикач, доки node-mysql їх не має?
funseiki

Це своєрідне питання про курку та яйця. Я не активно розробляю свій драйвер, тому що більшість людей використовують @ felixge's, я, мабуть, спробую знайти час, щоб перенести підготовлені оператори на node-mysql, оскільки це справді дає певні переваги продуктивності (і потенційно ускладнює ін'єкції sql). Не соромтеся коментувати / публікувати питання, якщо ви вирішите спробувати
Андрій Сидоров,

1
@funseiki Я впевнений, що підготовлені твердження були б найкращим рішенням, але я впевнений, що екранування запобіжить введенню SQL. Оскільки сам модуль підтримується Joyent, модуль активний і, очевидно, ретельно перевірений. Якби цей модуль не був готовий до виробництва, то я не думаю, що модуль мав би мати в середньому 1000 завантажень / день минулого місяця. Зверніть увагу, що node-mysql-native проходить 6 місяців з моменту останньої розробки, а node-mysql дуже активний, і над ним працює кілька людей.
гексаціанід

@AndreySidorov Дякую за коментар - якщо я спробую вирішити це питання, я опублікую оновлення. Я не думаю, що це буде найближчим часом, однак, оскільки, схоже, з ним буде легко поводитися (з ним буде потрібно більше досліджень, ніж я маю на даний час). Також дякую, що зробили цей драйвер - ви, хлопці, є причиною, за допомогою якої Node.js дозволяє швидко запускати програми
funseiki

@hexacyanide Оскільки node-mysql настільки популярний, я сподівався, що зможу отримати відповідь від членів спільноти щодо проблем безпеки, з якими вони могли зіткнутися (або запобігти), а також переконливий аргумент щодо того, чому поточний підхід до втечі символів безпечний достатньо для їх коду.
funseiki

12

Я усвідомлюю, що це старіший пост, але, схоже, відповіді так і не було позначено, тому я викину його туди.

Що стосується тестування, якщо модуль, який ви використовуєте, безпечний чи ні, є кілька шляхів, якими ви можете пройти. Я торкнусь плюсів / мінусів кожного, щоб ви могли прийняти більш обґрунтоване рішення.

На даний момент у модуля, який ви використовуєте, немає вразливих місць, однак це часто може призвести до помилкового відчуття безпеки, оскільки цілком може бути вразливість, яка зараз використовує модуль / програмний пакет, який ви використовуєте, і ви не отримаєте попередження до проблеми, доки постачальник не застосує виправлення / виправлення.

  1. Щоб бути в курсі вразливостей, вам потрібно буде стежити за списками розсилки, форумами, IRC та іншими дискусіями, пов’язаними з хакерством. ПРО: Часто ви можете дізнатися про потенційні проблеми в бібліотеці, перш ніж постачальник отримає попередження або випустить виправлення / виправлення, щоб виправити потенційну можливість атаки на його програмне забезпечення. ПРОТ: Це може зайняти багато часу та вимагати ресурсів. Якщо ви все-таки пройдете цей шлях, бот використовує RSS-канали, синтаксичний аналіз журналів (журнали чату IRC) та або веб-скрепер із використанням ключових фраз (у цьому випадку node-mysql-native), а сповіщення можуть допомогти скоротити час, витрачений на тролінг цих ресурсів.

  2. Створіть fuzzer, використовуйте fuzzer або інший фреймворк вразливості, такий як metasploit , sqlMap тощо, щоб допомогти перевірити проблеми, які постачальник не шукав. ПРО: Це може виявитись надійним методом забезпечення до прийнятного рівня незалежно від того, безпечний для загального доступу модуль / програмне забезпечення, яке ви впроваджуєте. ПРОТИ: Це також стає трудомістким і дорогим. Інша проблема буде пов’язана з помилковим спрацьовуванням, а також з непросвіченим переглядом результатів, якщо проблема існує, але її не помічають.

Дійсно безпека та безпека додатків загалом може зайняти багато часу та затратити багато ресурсів. Одне, що менеджери завжди використовуватимуть, - це формула для визначення економічної ефективності (трудових ресурсів, ресурсів, часу, заробітної плати тощо) виконання двох вищезазначених варіантів.

У будь-якому випадку, я усвідомлюю, що це не відповідь "так" чи "ні", на яку, можливо, сподівались, але я не думаю, що хтось може дати вам це, поки не проведе аналіз відповідного програмного забезпечення.


3

Я знаю, що це питання застаріле, але для всіх, хто цікавиться, Mysql-native був застарілим, тому ним став MySQL2 - це новий модуль, створений за допомогою команди оригінального модуля MySQL. Цей модуль має більше можливостей, і я думаю, що він має те, що ви хочете, оскільки він підготував оператори (за допомогою .execute ()) як у PHP для більшої безпеки.

Він також дуже активний (остання зміна була від 2-1 днів), я раніше не пробував, але, думаю, це те, що ви хочете, і багато іншого.


-1

Найпростіший спосіб - це обробляти всі ваші взаємодії з базою даних у власному модулі, який ви експортуєте до своїх маршрутів. Якщо ваш маршрут не має контексту бази даних, тоді SQL все одно не може його торкнутися.


Це насправді не відповідає на питання ОП про те, як дезінфікувати.
Крістофер,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.