В этой главе, посвящённой безопасности Node.js, вы узнаете, как защитить свои приложения от наиболее распространённых атак.

This article was translated to Russian by Andrey Melikhov, a front-end developer from Yandex.Money and editor of the collective blog about front-end, devSchacht. Find Andrey on: Twitter, GitHub, Medium & SoundCloud

Read the original article in English: Node.js Security Tutorial.

Перевод этой статьи сделан Андреем Мелиховым, фронтенд-разработчиком из компании Яндекс.Деньги, редактором коллективного блога о фронтенде, devSchacht. Twitter | GitHub | Medium | SoundCloud



Node.js и угрозы безопасности

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

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

Мы должны исправить это. Если вы разрабатываете программное обеспечение, безопасность является частью вашей работы.

Начало учебника по безопасности Node.js

Давайте начнём и защитим наше приложение Node.js путём правильного отношения к написанию кода, использованию утилит и эксплуатации!

Правило 1: Не используйте eval

Использование eval может сделать приложение уязвимым для атак с инъекцией кода. Старайтесь не использовать его, но если вам нужно, никогда не отправляйте непровалидированный пользовательский ввод в eval.

Явный вызов eval — это не единственное, что вам следует избегать, в фоновом режиме каждое из следующих выражений использует eval:

  • setInterval(String, 2)
  • setTimeout(String, 2)
  • new Function(String)

Правило 2: Всегда используйте строгий режим

С помощью use strict вы можете использовать ограниченный «вариант» JavaScript. Он устраняет бесшумность некоторых ошибок и делает их явными.

'use strict'
delete Object.prototype
// TypeError
var obj = {
    a: 1,
    a: 2
}
// Синтаксическая ошибка

Правило 3: Обращайтесь с ошибками аккуратно

Во время различных ошибочных сценариев ваше приложение может выдавать конфиденциальные сведения о внутренней инфраструктуре, например: X-Powered-By: Express.

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

Правило 4: Используйте статический анализ вашего кода

Статический анализ кода вашего приложения может поймать много ошибок. Для этого мы предлагаем использовать ESLint с JavaScript Standard Style.

Безопасное использование ваших сервисов в продакшене

Использование правильного стиля кода недостаточно для эффективной защиты Node.js — вы также должны быть осторожны в том, как вы запускаете свои сервисы в продакшене.

Правило 5: Не запускайте свои процессы с правами суперпользователя

К сожалению, мы это встречаем довольно часто: разработчики запускают своё Node.js-приложение с правами суперпользователя, так как они хотят, чтобы приложение слушало порт 80 или 443.

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

Вместо этого вы можете настроить HTTP-сервер/прокси для пересылки запросов. Это может быть nginx или Apache. Ознакомьтесь с нашей статьёй об использовании Node.js в продакшене, чтобы узнать больше.

Правило 6: Настройте обязательные HTTP-заголовки

Существуют определённые HTTP-заголовки, связанные с безопасностью, которые должен установить ваш сайт. Эти заголовки:

  • Strict-Transport-Security обеспечивает безопасные (HTTP через SSL/TLS) подключения к серверу
  • X-Frame-Options обеспечивает защиту от кликджекинга
  • X-XSS-Protectio включает XSS-фильтр, встроенный в большинство современных веб-браузеров
  • X-Content-Type-Options содержит инструкции по определению типа файла по content-type и не допускает MIME-сниффинг контента
  • Content-Security-Policy предотвращает широкий спектр атак, включая межсайтовый скриптинг и другие межсайтовые инъекции

В Node.js их легко установить с помощью модуля Helmet:

var express = require('express')
var helmet = require('helmet')

var app = express()
app.use(helmet())

Шлем также доступен для Koa: koa-helmet.

Правило 7: Правильное управление сессией

Для каждого cookie-файла должен быть указан следующий список флагов:

  • secure — этот атрибут говорит браузеру только отправлять cookie, если запрос отправляется через HTTPS.
  • HttpOnly — этот атрибут используется для предотвращения атак, таких как межсайтовый скриптинг, поскольку он не позволяет получить доступ к файлу cookie через JavaScript.

Правило 8: установка области видимости cookie-файлов

  • domain — этот атрибут используется для сравнения с доменом сервера, на котором запрашивается URL. Если домен соответствует или является субдоменом, тогда будет проверен атрибут path.
  • path — в дополнение к домену может быть указан путь URL, по которому действителен файл cookie. Если домен и путь совпадают, cookie будет отправлен в запросе.
  • expires — этот атрибут используется для установки постоянных файлов cookie, поскольку cookie не истекает, пока не будет превышена установленная дата.

В Node.js вы можете легко создать этот файл cookie, используя пакет cookie. Опять же, это довольно низкий уровень, поэтому вы, вероятно, в конечном итоге будете использовать обёртку, например, cookie-session.

var cookieSession = require('cookie-session')
var express = require('express')

var app = express()

app.use(cookieSession({
    name: 'session',
    keys: [
        process.env.COOKIE_KEY1,
        process.env.COOKIE_KEY2
    ]
}))

app.use(function (req, res, next) {
    var n = req.session.views || 0
    req.session.views = n++
    res.end(n + ' views')
})

app.listen(3000)

(Этот пример взят из документации модуля cookie-session)

Полезные инструменты

Поздравляю, вы почти закончили! Если вы следовали этому руководству и тщательно выполнили предыдущие шаги, у вас останется только одна область, касающаяся безопасности Node.js. Давайте перейдём к использованию надлежащих инструментов для поиска уязвимостей модулей!

Правило 9: Ищите уязвимости с Retire.js

«Всегда ищите уязвимости в своих модулях nodejs. Вы то, что вы реквайрите.»

Цель Retire.js - помочь вам определить использование версий модулей с известными уязвимостями.

Просто установите:

npm install -g retire

После этого запуск с помощью команды retire будет искать уязвимости в вашем каталоге node_modules. (Также обратите внимание, что retire.js работает не только с Node.js-модулями , но и с фронтенд-библиотеками.)

Правило 10: Проводите аудит ваших модулей с помощью CLI Node Security Platform

nsp является основным командной строки для Node Security Platform. Он позволяет производить аудит файлов package.json или npm-shrinkwrap.json с помощью API NSP для выявления уязвимых модулей.

npm install nsp --global
# Внутри директории вашего проекта
nsp check

Безопасность Node.js не является большой проблемой после того, как вы это прочитали? Надеюсь, вы нашли, что эти правила будут полезны для защиты ваших Node.js-приложений, и и будете следовать им в будущем, поскольку безопасность является частью вашей работы!

Если вы хотите больше узнать о безопасности Node.js, я могу порекомендовать эти статьи:


В следующей главе Node Hero вы узнаете, как развернуть защищённое Node.js-приложение, чтобы люди могли начать его использовать!