Как защитить приложение Nodejs.

Эта статья о том, как улучшить систему безопасности нашего nodejs-приложения от атак и взломов. Но сначала нам нужно знать, что означает node.js. Node.js чрезвычайно популярен в наши дни, в первую очередь в качестве бэкенд-сервера для веб-приложений. Однако в мире микросервисов его можно встретить практически везде, играя различные и важные роли в большом стеке приложений. Одним из преимуществ Node.js является возможность установки дополнительных модулей, что с точки зрения безопасности дает больше возможностей для открытия «черных ходов».

Кроме того, чем популярнее фреймворк, тем больше шансов, что хакеры попытаются найти уязвимости. Поэтому к безопасности Node.js всегда следует относиться серьезно. Разработчику свойственно рассматривать в конце цикла разработки «безопасность» приложения. Безопасное приложение — это не роскошь, а необходимость. Вы должны думать о безопасности вашего приложения на каждом этапе разработки, таком как архитектура, дизайн, код и, наконец, развертывание. Как уже было сказано, что же это за уязвимости или лазейки, которые хакер стремится найти? Мы поговорим о них, а также о решении…

Распространенные атаки на приложения node js:

  • SQL Injection;
  • Межсайтовый скриптинг (XSS);
  • Грубая сила.
  • SQL Injection: Атака SQL-инъекции — это когда SQL-запрос «впрыскивается» в базу данных вашего веб-приложения.

  • Межсайтовый скриптинг (XSS): Межсайтовый скриптинг — это еще один тип инъекционной атаки, которая возникает, когда злоумышленник вводит вредоносный код на легитимный веб-сайт, используя пользовательский ввод.

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

Это распространенные атаки, и поэтому нам необходимо защитить наши приложения node.js; ниже приведены решения этих атак:

Валидация пользовательского ввода для ограничения SQL-инъекций и XSS-атак

Начнем с одной из самых популярных атак — SQL-инъекции. Как следует из названия, атака SQL-инъекции происходит, когда хакер может выполнять SQL-запросы в вашей базе данных. Это становится возможным, если вы не санируете входные данные с фронт-энда. Другими словами, если ваш бэкенд Node.js берет параметр из данных, предоставленных пользователем, и использует его непосредственно как часть SQL-запроса.

Вы всегда должны проверять или санировать данные, поступающие от пользователя или другого субъекта системы. Плохая валидация или полное отсутствие валидации представляет угрозу для работающей системы и может привести к эксплойту безопасности. Также следует экранировать выходные данные. Давайте узнаем, как валидировать входящие данные в Node.js. Для проверки данных можно использовать модуль node под названием validator. Например.

const validator = require('validator');
validator.isEmail('foo@bar.com'); //=> true
validator.isEmail('bar.com'); //=> false

Вход в полноэкранный режим Выход из полноэкранного режима

Вы также можете использовать модуль под названием Joi для выполнения проверки данных/схемы. Например :

const joi = require('joi');
  try {
    const schema = joi.object().keys({
      name: joi.string().min(3).max(45).required(),
      email: joi.string().email().required(),
      password: joi.string().min(6).max(20).required()
    });

    const dataToValidate = {
        name: "Victor",
        email: "abc.com",
        password: "123456",
    }
    const result = schema.validate(dataToValidate);
    if (result.error) {
      throw result.error.details[0].message;
    }    
  } catch (e) {
      console.log(e);
  }
Войти в полноэкранный режим Выход из полноэкранного режима

Для предотвращения атак SQL Injection необходимо санировать входные данные. Вы можете либо проверять каждый отдельный ввод, либо проверять с помощью привязки параметров. Привязка параметров чаще всего используется разработчиками, поскольку она обеспечивает эффективность и безопасность. Если вы используете популярные ORM, такие как sequelize, hibernate и т.д., то они уже предоставляют функции для проверки и санации данных. Если вы используете модули баз данных, отличные от ORM, такие как mysql для Node или Mongoose, вы можете использовать методы экранирования, предоставляемые модулем. Давайте разберемся на примере. В приведенной ниже кодовой базе используется модуль mysql для Node.

var mysql = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'me',
  password : 'secret',
  database : 'my_db'
});

connection.connect();

connection.query(
    'UPDATE users SET ?? = ? WHERE ?? = ?',
    ['first_name',req.body.first_name, ,'id',1001],
    function(err, result) {
    //...
});
Вход в полноэкранный режим Выход из полноэкранного режима

Это также относится к межсайтовому скриптингу (XSS), но разница в том, что вместо отправки вредоносного SQL злоумышленник может выполнить код javascript.

node
app.get('/find_product', (req, res) => {
  ...
  if (products.length === 0) {
    return res.send('<p>No products found for "' + req.query.product + '"</p>');
  }
  ...
});
Вход в полноэкранный режим Выход из полноэкранного режима

Как видно из приведенного выше фрагмента, все, что пользователь вводит в поле поиска, если оно не найдено в базе данных, будет отправлено обратно пользователю в неизменном виде. Это означает, что если злоумышленник поместит код JavaScript вместо названия продукта в строку поиска, будет выполнен тот же код JavaScript. Для проверки вводимых пользователем данных можно использовать валидатор js или xss-фильтры.

Аутентификация и авторизация приложения

Неработающий, слабый или неполный механизм аутентификации занимает второе место среди наиболее распространенных уязвимостей. Возможно, это связано с тем, что многие разработчики думают об аутентификации так: «У нас она есть, значит, мы в безопасности». В действительности слабую или непоследовательную аутентификацию легко обойти. Чувствительные данные, такие как пароли, должны надежно храниться в системе, чтобы злоумышленники не могли использовать конфиденциальную информацию не по назначению. Одним из решений является использование существующих решений аутентификации, таких как Okta или OAuth.
Если вы предпочитаете придерживаться собственных решений аутентификации Node.js, вам необходимо помнить несколько вещей. При создании паролей не используйте встроенную криптобиблиотеку Node.js; используйте Bcrypt или Scrypt.

const bcrypt = require('bcrypt');

const saltRounds = 10;
const password = "Some-Password@2020";

bcrypt.hash(
    password,
    saltRounds,
    (err, passwordHash) => {

    //we will just print it to the console for now
    //you should store it somewhere and never log or print it

    console.log("Hashed Password:", passwordHash);
});
Вход в полноэкранный режим Выход из полноэкранного режима
const bcrypt = require('bcrypt');

const incomingPassword = "Some-Password@2020";
const existingHash = "some-hash-previously-generated"

bcrypt.compare(
    incomingPassword,
    existingHash,
    (err, res) => {
        if(res && res === true) {
            return console.log("Valid Password");
        }
        //invalid password handling here
        else {
            console.log("Invalid Password");
        }
});
Войти в полноэкранный режим Выход из полноэкранного режима

Обязательно ограничьте количество неудачных попыток входа и не сообщайте пользователю, что имя пользователя или пароль неверны. Вместо этого возвращайте общую ошибку «неверные учетные данные». Вам также необходимы соответствующие политики управления сессиями. И не забудьте внедрить аутентификацию 2FA. Если все сделано правильно, это может значительно повысить безопасность вашего приложения. Это можно сделать с помощью таких модулей, как node-2fa или speakeasy.

Избегайте ошибок, которые раскрывают слишком многое

Следующий пункт в списке — обработка ошибок. Здесь нужно учесть несколько моментов. Во-первых, не позволяйте пользователю узнать подробности, то есть не возвращайте клиенту полный объект ошибки. Он может содержать информацию, которую вы не хотите раскрывать, например, пути, другую используемую библиотеку или, возможно, даже секреты. Во-вторых, оберните маршруты с помощью условия catch и не позволяйте Node.js аварийно завершать работу, если ошибка была вызвана запросом.

Это не позволит злоумышленникам находить вредоносные запросы, которые приведут к краху вашего приложения, и отправлять их снова и снова, заставляя ваше приложение постоянно падать. Говоря о наводнении вашего приложения Node.js вредоносными запросами, не выставляйте ваше приложение Node.js напрямую в Интернет. Используйте какой-нибудь компонент перед ним, например, балансировщик нагрузки, облачный брандмауэр или шлюз, или старый добрый Nginx. Это позволит вам ограничить скорость DoS-атак за один шаг до того, как они поразят ваше приложение Node.js.

Заголовки безопасности HTTP

HTTP предоставляет несколько заголовков безопасности, которые могут предотвратить широко известные атаки. Если вы используете фреймворк Express, вы можете использовать модуль под названием helmet для включения всех заголовков безопасности с помощью одной строки кода.

npm install helmet --save
Вход в полноэкранный режим Выход из полноэкранного режима
const express = require("express"); 
const helmet = require("helmet");  
const app = express(); 
app.use(helmet());  
//...
Вход в полноэкранный режим Выйти из полноэкранного режима

Это включает следующие HTTP-заголовки.

  • Strict-Transport-Security
  • X-frame-Options
  • X-XSS-Protection
  • X-Content-Type-Protection
  • Content-Security-Policy
  • Cache-Control
  • Expect-CT
  • Отключить X-Powered-By

Эти заголовки предотвращают злоумышленников от различных типов атак, таких как clickjacking, межсайтовый скриптинг и т.д.

Проверка зависимостей

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

npm audit
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы устранить уязвимость, вы можете выполнить эту команду.

npm audit fix
Войти в полноэкранный режим Выйти из полноэкранного режима

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

npm audit fix --dry-run --json
Войти в полноэкранный режим Выйти из полноэкранного режима

Настройка протоколирования и мониторинга

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

Используйте линтеры безопасности

Мы уже говорили об автоматическом сканировании уязвимостей, но вы можете пойти еще дальше и выявлять распространенные уязвимости безопасности еще во время написания кода. Как? С помощью плагинов-линтеров, таких как eslint-plugin-security. Плагин безопасности будет уведомлять вас каждый раз, когда вы используете небезопасные методы работы с кодом (например, использование eval или нелитеральных выражений regex).

Избегайте секретов в конфигурационных файлах

Написание безопасного кода с самого начала поможет, но это не сделает ваше приложение пуленепробиваемым, если в итоге вы будете хранить секреты в виде обычного текста в файлах конфигурации. Такая практика неприемлема, даже если вы храните код в закрытом репозитории. Импорт секретов из переменных окружения — это первый шаг, но и он не является идеальным решением. Чтобы быть более уверенным в том, что ваши секреты нельзя легко прочитать, используйте решения для управления секретами, такие как Vault. Если использование Vault невозможно, шифруйте свои секреты при хранении и регулярно меняйте их. Многие решения CI/CD позволяют безопасно хранить секреты и безопасно развертывать их.

Надеюсь, эти рекомендации по безопасности приложений node.js будут вам полезны.

Заключение

Node.js — это ключевое решение для стартапов, позволяющее быстро упростить разработку, и сложная экосистема, принятая ведущими предприятиями. Даже самые надежные из всех сокровищ нуждаются в защите от краж и атак. А когда вы используете самый ценный веб-фреймворк для своего ценного проекта, вы, конечно, хотите защитить его от взлома. Поэтому мы должны быть внимательны к безопасности приложений nodejs.

Оцените статью
devanswers.ru
Добавить комментарий