Безопасность Node JS

Безопасность Node JS

Думаю, не нужно объяснять, что каждый год разработчики получают новые фреймворки для веб-разработки. Раньше для бэкэнда хватало одного лишь PHP, но сейчас мы не можем представить современную разработку без той же ноды или джанго.

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

Мы базово познакомимся с безопасностью NodeJS, дабы понимать, какие типовые и не совсем очевидные для начинающего разработчика уязвимости могут быть на веб-сайте.

Для кого эта статья

Это не статья по программированию. Она написана для начинающих пентестеров и разработчиков, которым интересно узнать, как именно работают современные веб технологии и как типовые веб уязвимости выглядят в рамках исходного кода. Такая практика, очевидно, может пригодится для пентеста в рамках White Box и для новичков в CTF вида Attack Defense, которые хотят познакомиться с «ручным» анализом кода.

NodeJS

Давайте немного разберемся, что из себя вообще представляет нода.

До недавних пор JS был исключительно клиентским языком программирования, но с приходом ноды ситуация изменилась: теперь на JS можно писать и бэкенд.

А теперь давайте перейдем к типовым уязвимостям и разберемся, что может пойти не так.

SQL Injections. Или не совсем SQL....

Вообще, правильнее говорить NoSql инъекции, т.к в большинстве случаев Node JS работает в связке с MongoDB, которая в свою очередь не является реляционной базой данных.

Если слово NoSql вам не знакомо, то объясню на пальцах: в NoSql нет строго типизированных запросов, они строятся, например, с помощью Json. Там нет четкой привязки к определенному синтаксису.

Объяснение очень срезанное, но давайте разберемся на практике, например мы хотим найти заданный юзернейм и пароль. Можно прописать в коде такой запрос:

database.table_users.find({ user: username, pass: password })

Вообще, NoSql не уникальны только для NodeJs. Но существует аббревиатура MEAN (mongoDB + ExpressJS + AngularJS + NodeJS), которая представляет из себя канонический набор технологий для приложений, чья серверная часть написана на JS, поэтому очень часто в проектах NodeJS будет использована именно MongoDB.

Давайте рассмотрим следующий участок кода:

app.post('/login', function (req, res) {
 database.table_users.find(
 { user: req.body.username, pass: req.body.password },
 .......................
 )
})

В данном примере никак не фильтруются входные значения для страницы входа в аккаунт, т.е наш десерелизованный JSON объект может содержать любые данные, включая полезную нагрузку для инъекции в базу данных, но у нас нет типизированного синтаксиса, как в SQL, ибо в любой NoSql базе данных свой собственный, самописный синтаксис.

Но есть как минимум одна интересная техника, приводящая к так называемой NoSql injection.

В MongoDB базах существует конструкция $gt. Она расшифровывается, как GreaterThan, т.е заменяет привычный нам знак «>». Используется такая конструкция, собственно, для выборки данных по признаку «больше».

Давайте рассмотрим пример:

database.food_price.find({ food: apple, price: { $gt: 20 }})

Т.е мы обращаемся к базе данных food_price и хотим получить ответ со всеми яблоками, цена которых больше 20 условных единиц. Результатом такого запроса будет JSON ответ с интересующей нас выборкой.

Но что если мы используем такой оператор, да еще и без фильтрации в злых целях?

Вернемся к прошлому примеру и изменим запрос поиска базы данных, ввод которого мы контролируем:

{
 "user": admin,
 "pass": {"$gt": ""}
}

Т.е мы обращаемся к базе данных table_users и просим дать нам доступ в личный кабинет с данными: admin, и с паролем, где пароль админа из базы данных будет больше пустой строки. Но мы же понимаем, что пароль в базе данных будет больше пустой строки? Значит, условие сработает и вернет true, соответственно мы обойдем проверку и получим доступ к аккаунту админа. Своеобразная адаптация ‘ or 1=1 -- пейлоада из мира SQL инъекций.

Ремарка:
Если тело запроса посылается в виде user=admin&password=pass
Мы все равно может провести инъекцию следующим образом:
user=admin&password[$gt]=

Такое возможно благодаря специальному синтаксису ExpressJS, который так же используется в связке с NodeJS. Т.е это аналогично JSON запросам выше.

Небезопасные функции и пользовательский ввод

Наверняка вы знакомы с понятием функций в языках программирования. Некоторые из этих функций позволяют выполнять любые команды в системе.

Таких функций может быть несколько, но суть одна: ни при каких обстоятельствах в них нельзя передавать пользовательский ввод, особенно не фильтрованный.

Eval()

Эта функция выполняет строку кода, например:

let code = 'alert("Привет")';
eval(code);

Т.е передача пользовательского ввода в eval может вызвать ту же XSS или что-то посерьезнее при должных навыках программирования. Например такой функционал может быть использован для создания простого калькулятора в окне.

Пример кода:

let code = prompt("Введите выражение:", 'USER_INPUT');
alert(eval(code));

Т.е при вводе в USER_INPUT в окне prompt мы можем стандартно перемножить два числа, введя, например 2*2, либо внедрить alert(«Hacked») и получить XSS

setTimeout()

Данная функция может вызвать другую функцию в определенном интервале 

function alertHelloWorld()
{
alert('Hello World');
}

setTimeout(alertHelloWorld, 10000); 

В этом примере функция alertHelloWorld() будет вызвана спустя 10000 миллисекунд после выполнения строчки кода, но что если мы можем контролировать ввод в функцию setTimeout()?

setTimeout(EVIL_FUNC, 10000);

Верно, вместо EVIL_FUNC мы можем вызвать вредоносную функцию, которая снова может дать XSS.

child_process

В Node JS можно создавать несколько процессов при помощи модуля child_process.

Более того, можно создать подпроцессы, отсюда и название «дочерний процесс».

Например child_process.exec() создает в отдельном процессе отдельную оболочку терминала и выполняет команду, будь то ls или ping. Очевидно, что при пользовательском вводе без санитизации может возникнуть уязвимость OS Command Injection(внедрение системных команд).

В дополнение стоит отметить, что по дефолту Node JS передает все параметры запроса в обычный массив, что может привести к атаке HTTP Parameter Pollution, про защиту от которой мы еще поговорим чуть ниже.

Обязательно ограничивайте запросы

В Node JS можно сделать ограничение на длину определенного запроса, это нужно для того, чтобы злоумышленник не положил ваш сервер, сделано это с помощью raw body. Но стоит понимать, что ограничивать все подряд - глупо, т.к ваше приложение может принимать банальные файлы. Поэтому в функционале Express можно ограничить отдельные типы данных. Например, можно ограничить Json, но не ограничивать запросы, где идет отдача файла пользователем. При этом не нужно забывать про фильтрацию заголовка Content-Type, т.к злоумышленник может его подделать, и все ваши ограничения запроса сойдут на нет и злоумышленник сможет вызвать DOS атаку.

Атака HPP

Атака загрязнения запросов HTTP(HTTP Parameter Pollution) происходит тогда, когда злоумышленник подает в запросе несколько параметров с одинаковым именем, что приводит к аномалиям в ответах, которые записываются Express в один массив. Это можно использовать для дальнейших атак. Проблема решается просто: при помощи подключения модуля hpp.

Безопасность cookie сессии

Ни для кого не секрет, что многие атаки нацелены на захват сессии путем похищения cookie файлов. Сделать это можно посредством проведения многих атак, но защититься в Node JS от этого проще простого, добавив лишь одну строчку при объявлении и описании сессии в коде:

cookie: { secure: true, httpOnly: true, path: '/user', sameSite: true}

Лишь несколько флагов в виде httpOnly и sameSite сделают нерабочей и бесполезной с точки зрения воровства сессии очень популярную атаку XSS.

Заключение

Любая популярная веб технология помимо общих веб уязвимостей(SSRF, XSS, SQLInj и т.д) имеет специфичные(или более вероятные и популярные) уязвимости, которые вытекают из принципа работы или из-за популярных связок(те же NoSql базы данных).

Никогда не пренебрегайте более глубоким изучением технологий веб разработки для их последующей эксплуатации, ведь именно эти знания могут дать серьезную точку входа. На примере Node JS  это могут быть NoSql инъекции, а в том же Flask атаки SSTI.

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