Предотвращение SQL-инъекций в Node.js


87

Можно ли предотвратить SQL-инъекции в Node.js (желательно с помощью модуля) так же, как в PHP были подготовленные операторы, защищающие от них.

Если да, то как? Если нет, то каковы некоторые примеры, которые могут обойти предоставленный мной код (см. Ниже).


Некоторый контекст:

Я создаю веб-приложение с внутренним стеком, состоящим из Node.js + MySql, с использованием модуля node-mysql . С точки зрения юзабилити, модуль является большим, но это еще не реализовано что - то похожее на РНР Подготовленные заявления (хотя я знаю , что это на TODO ).

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

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

Должен ли я пока перейти на node-mysql-native , поскольку он предоставляет подготовленные операторы? Я не решаюсь сделать это, потому что он не кажется таким активным, как node-mysql (хотя это может просто означать, что он завершен).

Вот фрагмент кода регистрации пользователя, который использует модуль sanitizer вместе с синтаксисом, подобным подготовленному оператору 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?
   });

Ответы:


60

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


3
Как упоминалось в моем сообщении, я знаю, что библиотека экранирует символы, но меня больше беспокоят последствия для безопасности, если я не переключусь на библиотеку, в которой реализованы подготовленные операторы, т.е. существует ли SQL-инъекция, которая может произойти с тем, что Я сейчас делаю?
funseiki

2
Экранирующие символы предотвращают внедрение SQL. Инъекции происходят, когда символы не экранированы, и злоумышленники могут воспользоваться этим, чтобы закрыть запрос и запустить новый, например, для удаления таблицы или вставки поддельной записи. С экранированными символами это невозможно. В Википедии есть дополнительная информация о SQL-инъекции.
Майкл Пратт

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

Помимо этих функций, вы также можете использовать escape-функции:

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

Чтобы избежать идентификаторов запроса:

mysql.escapeId(identifier);

И в ответ на ваш комментарий к подготовленным заявлениям:

С точки зрения удобства использования, модуль великолепен, но он еще не реализовал что-то вроде подготовленных операторов PHP.

Подготовленные операторы находятся в списке задач для этого коннектора, но этот модуль, по крайней мере, позволяет вам указывать настраиваемые форматы, которые могут быть очень похожи на подготовленные операторы. Вот пример из ридми:

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. Я, вероятно, постараюсь найти время для переноса подготовленных операторов в node-mysql, поскольку это действительно дает некоторые преимущества в производительности (и потенциально затрудняет SQL-инъекции). Не стесняйтесь комментировать / публиковать вопросы, если решите попробовать
Андрей Сидоров

1
@funseiki Я уверен, что подготовленные операторы будут лучшим решением, но я уверен, что экранирование предотвратит SQL-инъекции. Поскольку сам модуль поддерживается Joyent, модуль активен и, очевидно, тщательно проверен. Если бы этот модуль не был готов к производству, то я не думаю, что в прошлом месяце у него было бы в среднем 1000 загрузок в день. Обратите внимание, что node-mysql-native прошло 6 месяцев с момента его последней разработки, а node-mysql очень активен, и над ним работают несколько человек.
гексацианид

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

@hexacyanide Поскольку node-mysql настолько популярен, я надеялся, что смогу получить ответ от членов сообщества относительно проблем безопасности, с которыми они могли столкнуться (или предотвратить), а также убедительный аргумент относительно того, почему текущий подход к экранированию символов безопасен достаточно для их кода.
фунсейки

12

Я понимаю, что это более старый пост, но кажется, что ответ никогда не был отмечен, поэтому я брошу его там.

Что касается тестирования того, является ли модуль, который вы используете, безопасным или нет, вы можете выбрать несколько маршрутов. Я коснусь плюсов и минусов каждого, чтобы вы могли принять более обоснованное решение.

В настоящее время нет никаких уязвимостей для модуля, который вы используете, однако это часто может привести к ложному чувству безопасности, так как вполне может быть уязвимость, которая в настоящее время использует модуль / программный пакет, который вы используете, и вы не будете предупреждены к проблеме, пока поставщик не применит исправление / патч.

  1. Чтобы быть в курсе уязвимостей, вам нужно будет подписаться на списки рассылки, форумы, IRC и другие обсуждения, связанные с взломом. PRO: Вы можете часто узнавать о потенциальных проблемах в библиотеке до того, как поставщик был предупрежден или выпустил исправление / патч, чтобы устранить потенциальную возможность атаки на его программное обеспечение. ПРОТИВ: Это может занять очень много времени и ресурсов. Если вы действительно пойдете по этому пути, бот будет использовать RSS-каналы, парсинг журналов (журналы IRC-чатов) и / или веб-парсер с использованием ключевых фраз (в данном случае node-mysql-native) и уведомления могут помочь сократить время, потраченное на троллинг этих ресурсов.

  2. Создайте фаззер, используйте фаззер или другую структуру уязвимостей, например metasploit , sqlMap и т. Д., Чтобы помочь проверить проблемы, которые поставщик, возможно, не искал. ЗА: Это может оказаться верным методом проверки на приемлемом уровне того, безопасен ли модуль / программное обеспечение, которое вы внедряете, для публичного доступа. ПРОТИВ: Это также требует много времени и средств. Другая проблема будет возникать из-за ложных срабатываний, а также из-за необразованного анализа результатов, когда проблема присутствует, но не замечена.

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

В любом случае, я понимаю, что это не ответ «да» или «нет», на который, возможно, надеялись, но я не думаю, что кто-то может дать вам это, пока не проведет анализ рассматриваемого программного обеспечения.


3

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

Он также очень активен (последнее изменение было от 2 до 1 дня). Я не пробовал его раньше, но я думаю, что это то, что вы хотите, и многое другое.


-1

Самый простой способ - обрабатывать все взаимодействия с базой данных в собственном модуле, который вы экспортируете в свои маршруты. Если ваш маршрут не имеет контекста базы данных, SQL все равно не сможет его коснуться.


Это на самом деле не отвечает на вопрос OP о том, как дезинфицировать.
Кристофер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.