Вы пишете на JavaScript и думаете, что безопасность — это не ваша забота? Ошибаетесь. Почти 70% веб-приложений имеют уязвимости, и большинство из них связаны с фронтендом. В этой статье мы разберём, как писать код так, чтобы злоумышленник не украл данные ваших пользователей и не превратил ваш сайт в зомби-сеть.

Digital-студия WNDER

Почему JavaScript — лакомая цель для хакеров

JavaScript выполняется прямо в браузере пользователя. Это значит, что любой может открыть консоль разработчика и посмотреть, как работает ваш код. А ещё — найти дыры. Самое частое: вы вставляете данные от пользователя прямо в HTML без проверки. Или храните секретные ключи в открытом виде. Или доверяете данным с клиента так, будто это святое писание.

Давайте разберём основные угрозы и как от них защититься.

XSS: когда ваш сайт начинает работать на хакера

XSS (Cross-Site Scripting) — это как если бы в ваш дом залез вор и начал выдавать себя за вас. Злоумышленник вставляет свой JavaScript-код на вашу страницу, и он выполняется в браузере жертвы. Может украсть куки, пароли, перенаправить на фишинговый сайт.

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

// ПЛОХО: прямое использование данных пользователя
const userInput = document.getElementById('comment').value;
document.getElementById('output').innerHTML = userInput;

Если пользователь введёт <script>alert('взлом')</script>, скрипт выполнится. Вот как надо:

// ХОРОШО: экранирование или textContent
const userInput = document.getElementById('comment').value;
document.getElementById('output').textContent = userInput;
// или использовать библиотеку для очистки, например DOMPurify
Правило: Никогда не вставляйте пользовательские данные через innerHTML, document.write или eval. Используйте textContent или проверенные библиотеки санитайзинга.

Также всегда устанавливайте заголовок Content-Security-Policy (CSP). Он запрещает выполнение сторонних скриптов.

CSRF: как заставить пользователя сделать то, чего он не хочет

CSRF (Cross-Site Request Forgery) — это когда злоумышленник заставляет вашего пользователя отправить запрос от его имени. Например, перевести деньги или сменить пароль. Пользователь просто заходит на вредоносный сайт, а тот шлёт запрос на ваш сервер, используя куки жертвы.

Защита проста: используйте токены CSRF. Сервер генерирует случайный токен, вставляет его в форму, а при отправке проверяет. Если токен не совпадает — отказ.

Пример на Node.js с Express:

const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

app.get('/form', csrfProtection, (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});

app.post('/process', csrfProtection, (req, res) => {
  // обрабатываем данные
});

В форме на клиенте добавьте скрытое поле с токеном:

<form action="/process" method="POST">
  <input type="hidden" name="_csrf" value="{{csrfToken}}">
  <!-- остальные поля -->
</form>
Лайфхак: Для API используйте проверку заголовка Origin или Referer. Но токены надёжнее.

Инъекции в JavaScript: не только SQL

Инъекции бывают разные: SQL, NoSQL, командные. В JavaScript-приложениях часто страдают запросы к базам данных, если вы склеиваете строки. Например, в MongoDB:

// ПЛОХО: конкатенация строк
const query = { username: req.body.username, password: req.body.password };
// Если злоумышленник передаст { "$ne": null }, он войдёт без пароля

Правильно использовать параметризованные запросы или ORM. В Mongoose:

// ХОРОШО: явное приведение типов
const username = String(req.body.username);
const password = String(req.body.password);
const user = await User.findOne({ username, password });

Всегда проверяйте типы данных. Не доверяйте тому, что приходит с клиента.

Безопасность зависимостей: ваш node_modules — мина

Средний проект на JavaScript тянет сотни пакетов. Каждый из них может содержать уязвимость. В 2021 году пакет ua-parser-js был взломан и воровал криптовалюту. Как защититься?

  • Регулярно запускайте npm audit и исправляйте проблемы.
  • Используйте npm outdated для проверки устаревших пакетов.
  • Подключайте только проверенные библиотеки с активным сообществом.
  • Фиксируйте версии в package-lock.json.

Вот таблица с основными инструментами для проверки зависимостей:

Инструмент Что делает Как использовать
npm audit Находит уязвимости в зависимостях npm audit
Snyk Сканирует код и зависимости npx snyk test
OWASP Dependency-Check Проверяет на известные CVE Интеграция в CI/CD

Практические советы для ежедневной работы

Вот несколько привычек, которые сделают ваш код безопаснее:

  • Используйте const и let вместо var — меньше шансов случайно перезаписать переменную.
  • Всегда проверяйте входные данные на стороне сервера, даже если уже проверили на клиенте.
  • Храните секреты (ключи API, пароли) в переменных окружения, а не в коде.
  • Настройте HTTPS и HSTS. Без шифрования любой может перехватить трафик.
  • Ограничьте права пользователей в базе данных — не давайте root-доступ приложению.
  • Логируйте подозрительные действия, но не пишите в логи пароли и токены.
Совет: Проведите аудит безопасности хотя бы раз в полгода. Пригласите стороннего специалиста — свежий взгляд найдёт то, что вы пропустили.

Что в итоге

Безопасность в JavaScript — это не пара трюков, а образ мышления. Всегда спрашивайте себя: «А что, если пользователь пришлёт что-то неожиданное?» Экранируйте вывод, проверяйте вход, используйте токены, следите за зависимостями. И помните: безопасность — это процесс, а не галочка в чек-листе.

Начните с малого: сегодня замените innerHTML на textContent и запустите npm audit. Завтра настроите CSP. Через месяц ваш проект станет крепче, а вы — спокойнее.

Студия WNDER