Опасная уязвимость в популярной библиотеке Sequelize

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!



Привет, Хабр! Данная статья будет интересна тем, кто уже использует библиотеку Sequelize или же только собирается с ней работать. Под катом мы расскажем, чем встроенный функционал operatorAliases может быть вреден и как избежать утечки из собственной базы данных.

Что такое Sequelize, где он используется и для чего?


Sequelize — это ORM-библиотека на Node.js для Postgres, MySQL, MariaDB, SQLite и Microsoft SQL Server, которая осуществляет сопоставление таблиц в бд и отношений между ними с классами. При использовании Sequelize мы можем не писать SQL-запросы, а должны работать с данными как с обычными объектами. Она имеет надежную поддержку транзакций, отношения, активную и отложенную загрузку, репликацию чтения и многое другое.

Что за опция operatorAliases, и в чем заключается ее опасность?


По умолчанию Sequelize использует операторы символов. Использование Sequelize без символьных псевдонимов, конечно, повышает безопасность. И хотя отсутствие строковых псевдонимов делает инъекцию операторов крайне маловероятной, мы всегда должны корректно проверять и очищать данные, вводимые пользователем.

А сама опция operatorAliases позволяет установить, будут ли доступны операторы-псевдонимы. Вот как выглядит пример активации в коде:



Когда все работает правильно


Рассмотрим код демо-приложения. Файл модели user.model.js содержит:



Видно, что в таблице пользователей есть три поля, и они все имеют строковой тип данных.

Файл контроллера auth.controller.js содержит:



В коде используется метод findOne к модели User. И метод findOne возвращает первую строку из базы данных, согласно переданному условию запроса. В данном случае, приложение получает от пользователя данные username и password, применяет их в запрос к таблице users.

Сгенерированный в данном случае запрос будет выглядеть примерно так:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = :username AND `users`.`password` = :password LIMIT 1;

Поскольку используется ORM для формирования запросов, банальная SQL-инъекция не сработает. Если в базе не найдется совпадений по пользователю, приложение вернет ошибку User Not found. В случае совпадений вводных данных на уровне базы данных приложение сравнит введенный пароль с паролем, хранящимся в базе, и либо вернет ошибку «Invalid Password!» при несовпадении, либо токен авторизации в случае успеха. Алгоритм проверки вводных данных выбран специально для тестирования уязвимости.

Таблица будет содержать такие данные:





Авторизация работает исправно.

А что же с операторами и псевдонимами?





Псевдонимы обозначаются символом “$”, синтаксис псевдонимов схож с MongoDB. Нам доступны операторы поиска, сравнения и многие другие. Не смотря на строгую типизацию данных в модели, передача данных от пользователя в ORM в формате JSON влечет за собой нормализацию. И тут начинается самое интересное!

Когда беда стучится в DOM


Групповая атака (Batching attack)




Такого вида запрос к приложению инициирует запрос к базе:
Executing (default): SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` IN ('admin', 'more', 'much more') AND `users`.`password` = 'wrong pass' LIMIT 1;

При помощи этой атаки можно за один запрос к серверу проверить на валидность много логинов на конкретный пароль и наоборот. Атака работает в последней на декабрь 2020 версии библиотеки (6.3.5) и при выключенной опции operatorsAliases.

Атака преобразования типов данных


Если передать приложению данные вида…



… то, ничего в нашем случае не произойдет. Логическое условие в базу данных хоть и будет правильным, проверка пароля в исследуемом приложении на уровне приложения и сравнение разных типов данных не может вернуть true.

Атака при помощи операторов сравнения




По данным на скришоте будет сгенерирован запрос в базу вида:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` != 'aaa' LIMIT 1;

База данных возвращает данные, так как есть совпадение username = admin и пароля, не равного “aaa”. Для того чтобы пройти процесс авторизации полностью, нам необходимо достать пароль.

Атака операторов регулярных выражений и поиска в строке


Получить исходные данные можно, используя псевдонимы операторов поиска $like или операторов для работы с регулярными выражениями $regexp.



Когда символ не сойдется, возникнет ошибка, что пользователь не найден.



Если символ сойдется, будет ошибка о неверном пароле. В базу выполняется запрос вида:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` LIKE 'E%' LIMIT 1;

Таким образом, посимвольно можно восстановить данные из таблицы.

Атака сравнения столбцов в таблице


Есть интересный псевдоним $col, который позволяет сравнить поле с полем.



Запрос в базу будет:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` = `aaaaa` LIMIT 1;



Выполнит в базу следующий запрос:
SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` = `password` LIMIT 1;
Тем самым выполнив логическое условие на уровне базы данных.

Избавляемся от уязвимостей


  • Необходимо установить последнюю версию библиотеки Sequalize, где была убрана поддержка псевдонимов.

    (Источник)
  • Отключить использование псевдонимов, установив значение operatorAliases: false.
  • Тщательно проверять типы и их значения данных от пользователя до их использования в ORM.

Спасибо за интерес!
Источник: https://habr.com/ru/company/wallarm/blog/539630/


Интересные статьи

Интересные статьи

Недавно на проекте интегрировал модуль CRM Битрикса c виртуальной АТС Ростелеком. Делал по стандартной инструкции, где пошагово показано, какие поля заполнять. Оказалось, следование ей не гаран...
Мы часто проводим пентесты для банков и других финансовых организаций. Так же часто обнаруживаем уязвимости разного уровня критичности. Этот пост — про один из таких кейсов. Недавн...
В обновлении «Сидней» Битрикс выпустил новый продукт в составе Битрикс24: магазины. Теперь в любом портале можно создать не только лендинг или многостраничный сайт, но даже интернет-магазин. С корзино...
На сегодняшний день у сервиса «Битрикс24» нет сотен гигабит трафика, нет огромного парка серверов (хотя и существующих, конечно, немало). Но для многих клиентов он является основным инструментом ...