В этой главе, посвящённой безопасности 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-приложение, чтобы люди могли начать его использовать!