Безопасность JavaScript приложений: топ-10 уязвимостей для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Безопасность JavaScript приложений: топ-10 уязвимостей для начинающих

Разработка на JavaScript, особенно в среде Node.js, открывает широкие возможности для создания современных веб-приложений. Однако вместе с мощью приходит и ответственность. Игнорирование вопросов безопасности может привести к утечке данных, финансовым потерям и репутационному ущербу. Для начинающих разработчиков понимание основных угроз — первый шаг к созданию защищённого кода. В этой статье мы разберём топ-10 уязвимостей JavaScript (Node.js) на основе списка OWASP, с примерами кода и практическими советами по защите.

1. Межсайтовый скриптинг (XSS)

XSS — одна из самых распространённых атак. Злоумышленник внедряет вредоносный скрипт в веб-страницу, который выполняется в браузере жертвы. В Node.js это часто происходит через неэкранированный вывод данных.

Пример уязвимого кода (Express):

app.get('/user/:name', (req, res) => {
  res.send('<h1>Привет, ' + req.params.name + '</h1>');
});

Как защититься: Используйте шаблонизаторы с автоэкранированием (например, Handlebars, EJS) или библиотеки вроде helmet. Никогда не вставляйте пользовательский ввод напрямую в HTML.

app.get('/user/:name', (req, res) => {
  const safeName = encodeURIComponent(req.params.name);
  res.send(`<h1>Привет, ${safeName}</h1>`);
});

2. SQL-инъекции

Если ваше приложение использует SQL-базу данных (например, PostgreSQL или MySQL), неправильная обработка запросов может привести к выполнению произвольного SQL-кода.

Уязвимый код:

const query = `SELECT * FROM users WHERE email = '${userInput}'`;
db.query(query, callback);

Решение: Всегда используйте параметризованные запросы или ORM (например, Sequelize, Prisma).

const query = 'SELECT * FROM users WHERE email = $1';
db.query(query, [userInput], callback);

3. Подделка межсайтовых запросов (CSRF)

CSRF-атака заставляет пользователя выполнить нежелательное действие на сайте, где он аутентифицирован. Например, перевести деньги или изменить пароль.

Защита: Используйте CSRF-токены. В Express популярна библиотека csurf (устарела, но заменена на csrf-csrf или встроенные решения фреймворков).

const csrf = require('csrf-csrf');
const { generateToken } = csrf();

app.post('/transfer', (req, res) => {
  const token = req.body._csrf;
  if (!validateToken(token)) {
    return res.status(403).send('CSRF атака');
  }
  // Выполнение перевода
});

4. Незащищённые зависимости

Node.js приложения используют тысячи пакетов из npm. Устаревшие или уязвимые зависимости — частая причина взломов.

Рекомендации:

  • Регулярно запускайте npm audit для проверки уязвимостей.
  • Используйте snyk или Dependabot для автоматического обновления.
  • Удаляйте неиспользуемые пакеты.

5. Небезопасная аутентификация и управление сессиями

Слабые пароли, отсутствие ограничения на количество попыток входа, неправильное хранение сессионных токенов — всё это ведёт к компрометации аккаунтов.

Лучшие практики:

  • Храните пароли в хэшированном виде (bcrypt, argon2).
  • Используйте JWT с коротким сроком жизни и refresh-токенами.
  • Установите лимит на попытки входа (rate limiting).
const bcrypt = require('bcrypt');
const saltRounds = 10;

// Регистрация
const hash = await bcrypt.hash(password, saltRounds);

// Вход
const match = await bcrypt.compare(inputPassword, hash);

6. Недостатки контроля доступа

Пользователь может получить доступ к данным или функциям, для которых у него нет прав. Например, изменение чужого профиля по ID.

Пример:

// Уязвимо: пользователь может передать чужой ID
app.put('/user/:id', (req, res) => {
  // Обновление без проверки прав
});

// Безопасно: проверяем, что ID принадлежит текущему пользователю
if (req.user.id !== parseInt(req.params.id)) {
  return res.status(403).send('Доступ запрещён');
}

7. Неправильная обработка ошибок и логирование

Утечка технической информации через сообщения об ошибках (стектрейсы, версии библиотек) помогает злоумышленникам.

Решение: В продакшене отключайте детальные ошибки. Используйте централизованное логирование с маскировкой чувствительных данных.

app.use((err, req, res, next) => {
  console.error(err.stack); // Логируем для себя
  res.status(500).send('Внутренняя ошибка сервера'); // Пользователю — общее сообщение
});

8. Небезопасная десериализация

Если вы используете JSON.parse() или eval() на данных от пользователя, это может привести к удалённому выполнению кода (RCE).

Опасный код:

const data = eval(req.body.code); // Никогда так не делайте!

Защита: Избегайте eval() и new Function(). Используйте безопасные парсеры (например, JSON.parse() с проверкой схемы через joi или zod).

9. Использование компонентов с известными уязвимостями

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

Блоги

Рекомендаций по книгам