Перевод книги Node Hero от RisingStack. Переведено с разрешения правообладателей.
В этой главе, посвящённой безопасности Node.js, вы узнаете, как защитить свои приложения от наиболее распространённых атак.
В настоящее время мы почти каждую неделю видим серьёзные нарушения безопасности, например, в случаях LinkedIn или MySpace. Во время этих атак было украдено огромное количество пользовательских данных, а также нанесён вред корпоративной репутации.
Исследования также показывают, что тикеты на ошибки, связанные с безопасностью, остаются открытыми в среднем в течение 18 месяцев в некоторых областях индустрии.
Мы должны исправить это. Если вы разрабатываете программное обеспечение, безопасность является частью вашей работы.
Давайте начнём и защитим наше приложение Node.js путём правильного отношения к написанию кода, использованию утилит и эксплуатации!
Использование eval
может сделать приложение уязвимым для атак с инъекцией кода. Старайтесь не использовать его, но если вам нужно, никогда не отправляйте непровалидированный пользовательский ввод в eval
.
Явный вызов eval
— это не единственное, чего вам следует избегать. В фоновом режиме каждое из следующих выражений использует eval:
setInterval(String, 2)
setTimeout(String, 2)
new Function(String)
С помощью use strict
вы можете использовать ограниченный «вариант» JavaScript. Он устраняет бесшумность некоторых ошибок и делает их явными.
'use strict'
delete Object.prototype
// TypeError
var obj = {
a: 1,
a: 2
}
// Синтаксическая ошибка
Во время различных ошибочных сценариев ваше приложение может выдавать конфиденциальные сведения о внутренней инфраструктуре, например: X-Powered-By: Express
.
Трассировки стека сами по себе не рассматриваются как уязвимости, но они часто показывают информацию, которая может быть интересна злоумышленнику. Предоставление отладочной информации в результате операций, генерирующих ошибки, считается плохой практикой. Вы должны всегда логировать их, но никогда не показывать пользователям.
Статический анализ кода вашего приложения может поймать много ошибок. Для этого мы предлагаем использовать ESLint с JavaScript Standard Style.
Использование правильного стиля кода недостаточно для эффективной защиты Node.js, вы также должны быть осторожны в том, как вы запускаете свои сервисы в продакшене.
К сожалению, мы это встречаем довольно часто: разработчики запускают своё Node.js-приложение с правами суперпользователя, так как они хотят, чтобы приложение слушало порт 80 или 443.
Это просто неправильно. В случае ошибки ваш процесс может привести к сбою всей системы, поскольку вы дали ему права на что угодно.
Вместо этого вы можете настроить HTTP-сервер/прокси для пересылки запросов. Это может быть nginx или Apache. Ознакомьтесь с нашей статьёй об использовании Node.js в продакшене, чтобы узнать больше.
Существуют определённые HTTP-заголовки, связанные с безопасностью, которые должен установить ваш сайт. Эти заголовки:
- Strict-Transport-Security обеспечивает безопасные подключения к серверу (HTTP через SSL/TLS)
- X-Frame-Options обеспечивает защиту от кликджекинга
- X-XSS-Protection включает 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())
Helmet также доступен для Koa: koa-helmet.
Для каждого cookie-файла должен быть указан следующий список флагов:
- secure — этот атрибут говорит браузеру отправлять cookie, только если запрос отправляется через HTTPS
- HttpOnly — этот атрибут используется для предотвращения атак, таких как межсайтовый скриптинг, поскольку он не позволяет получить доступ к файлу cookie через JavaScript
- 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. Давайте перейдём к использованию надлежащих инструментов для поиска уязвимостей модулей!
«Всегда ищите уязвимости в своих модулях Node.js. Вы то, что вы реквайрите.»
Цель Retire.js - помочь вам определить использование версий модулей с известными уязвимостями.
Просто установите:
npm install -g retire
После этого запуск с помощью команды retire
будет искать уязвимости в вашем каталоге node_modules
. Также обратите внимание, что Retire.js работает не только с Node.js-модулями, но и с фронтенд-библиотеками.
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-приложение, чтобы люди могли начать его использовать!
Слушайте наш подкаст в iTunes и SoundCloud, читайте нас на Medium, контрибьютьте на GitHub, общайтесь в группе Telegram, следите в Twitter и канале Telegram, рекомендуйте в VK и Facebook.