Безопасность JavaScript приложений: топ-10 уязвимостей
JavaScript, особенно в среде Node.js, стал основой современной веб-разработки. Однако его популярность делает приложения привлекательной целью для атак. Игнорирование вопросов безопасности может привести к утечке данных, финансовым потерям и репутационному ущербу. В этой статье мы разберем топ-10 наиболее критичных уязвимостей JavaScript (Node.js) приложений, основанных на стандарте OWASP Top 10, и покажем, как их предотвратить с помощью примеров кода.
1. Инъекции (Injection)
Инъекции остаются одной из самых опасных угроз. В контексте Node.js чаще всего встречаются SQL-инъекции и NoSQL-инъекции (например, в MongoDB).
Проблема
Прямая конкатенация пользовательского ввода в запросы к базе данных позволяет злоумышленнику выполнить произвольный код.
Пример уязвимого кода
const user = req.body.username;
const query = `SELECT * FROM users WHERE username = '${user}'`;
db.query(query, callback);
Решение
Используйте параметризованные запросы или ORM/ODM. Для MongoDB применяйте mongo-sanitize.
const query = 'SELECT * FROM users WHERE username = $1';
db.query(query, [user], callback);
2. Нарушение аутентификации и управления сессиями
Слабая аутентификация — прямой путь к компрометации аккаунтов.
Проблема
Использование предсказуемых токенов (например, JWT с алгоритмом none), хранение паролей в открытом виде или отсутствие ограничения на количество попыток входа.
Пример уязвимости
// JWT без проверки алгоритма
const token = jwt.sign({ user: 'admin' }, 'secret', { algorithm: 'none' });
Решение
- Всегда проверяйте алгоритм JWT:
jwt.verify(token, secret, { algorithms: ['HS256'] }). - Храните пароли через
bcryptилиargon2. - Внедрите лимит попыток входа (
express-rate-limit).
const bcrypt = require('bcrypt');
const saltRounds = 10;
const hash = await bcrypt.hash(password, saltRounds);
3. XSS (Межсайтовый скриптинг)
XSS позволяет внедрить вредоносный скрипт в веб-страницу, которая затем выполняется в браузере жертвы.
Проблема
Вывод пользовательского контента без экранирования, особенно при использовании Server-Side Rendering (SSR) в Next.js или Nuxt.js.
Уязвимый код (Express)
res.send(`<h1>Hello, ${req.query.name}</h1>`);
Решение
- Экранируйте вывод: используйте библиотеки
escape-htmlили шаблонизаторы с автоэкранированием (EJS, Pug). - Установите заголовок CSP (Content Security Policy):
helmet.contentSecurityPolicy().
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: { defaultSrc: ["'self'"] }
}));
4. Небезопасные прямые ссылки на объекты (IDOR)
Уязвимость возникает, когда пользователь может получить доступ к объектам (файлам, записям БД), зная или угадав их идентификатор.
Пример
app.get('/api/user/:id', (req, res) => {
// Нет проверки, что req.user.id === req.params.id
const user = db.findUser(req.params.id);
res.json(user);
});
Решение
Всегда проверяйте права доступа на уровне сервера.
if (req.user.id !== req.params.id) {
return res.status(403).send('Forbidden');
}
5. Небезопасная конфигурация безопасности
Это включает в себя использование стандартных учетных данных, отладочных режимов в production, а также неправильные настройки CORS.
Проблема
// Открытый CORS
app.use(cors({ origin: '*' }));
Решение
- Отключите
X-Powered-Byс помощьюhelmet.hidePoweredBy(). - Настройте CORS строго:
cors({ origin: 'https://myapp.com' }). - Не храните секреты в коде, используйте
.envфайлы.
6. Подделка межсайтовых запросов (CSRF)
CSRF заставляет пользователя выполнить нежелательное действие на сайте, где он аутентифицирован.
Пример атаки
Злоумышленник отправляет форму на ваш сайт от лица жертвы, используя её активную сессию.
Решение
Используйте CSRF-токены. В Express отлично работает пакет csurf (или его преемник csrf-csrf).
const csrf = require('csrf-csrf');
const { generateToken, doubleCsrfProtection } = csrf();
app.use(doubleCsrfProtection);
7. Использование компонентов с известными уязвимостями
Node.js проекты часто содержат сотни зависимостей. Устаревшие библиотеки — золотая жила для хакеров.
Проблема
Использование старой версии lodash или express с известными CVE.
Решение
- Регулярно запускайте
npm auditи исправляйте уязвимости. - Используйте
snykилиDependabotдля автоматического мониторинга. - Обновляйте зависимости:
npm update.
npm audit fix
8. Недостаточное логирование и мониторинг
Без логов вы не узнаете об атаке, пока