← Назад к вопросам
Что такое SQL injection и как защитить Node.js приложение от него?
3.0 Senior🔥 261 комментариев
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое SQL injection и как защитить Node.js приложение от него?
SQL Injection — это критическая уязвимость безопасности, при которой злоумышленник внедряет вредоносный SQL код в пользовательские входные данные.
Как происходит SQL Injection
const userId = req.query.id;
const query = `SELECT * FROM users WHERE id = ${userId}`;
// Если userId = "1 OR 1=1", то SELECT * FROM users WHERE id = 1 OR 1=1 вернёт ВСЕ пользователей
const username = req.body.username;
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '...'`;
// Если username = "admin' --", то -- комментарий игнорирует остаток запроса
1. Защита через Parameterized Queries
const mysql = require('mysql2/promise');
const connection = await mysql.createConnection({ ... });
const userId = req.query.id;
const [rows] = await connection.execute(
'SELECT * FROM users WHERE id = ?',
[userId]
);
2. ORM (Object-Relational Mapping)
Prisma
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
const userId = req.query.id;
const user = await prisma.user.findUnique({
where: { id: parseInt(userId) },
});
const users = await prisma.user.findMany({
where: { email: req.body.email },
});
TypeORM
const userRepository = getRepository(User);
const user = await userRepository.findOne({
where: { id: userId },
});
const users = await userRepository
.createQueryBuilder('user')
.where('user.email = :email', { email: req.body.email })
.getMany();
Sequelize
const user = await User.findByPk(userId);
const users = await User.findAll({
where: { email: req.body.email },
});
const user = sequelize.query(
'SELECT * FROM users WHERE email = ?',
{ replacements: [email], type: QueryTypes.SELECT }
);
3. Экранирование строк
const mysql = require('mysql2');
const userId = mysql.escape(req.query.id);
const query = `SELECT * FROM users WHERE id = ${userId}`;
4. Валидация входных данных
const { query, validationResult } = require('express-validator');
app.get('/users/:id',
query('id').isInt().toInt(),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const userId = req.query.id;
connection.query(
'SELECT * FROM users WHERE id = ?',
[userId],
(error, results) => res.json(results)
);
}
);
5. Белые списки (white lists)
const allowedSortFields = ['name', 'email', 'created_at'];
const sortBy = req.query.sort;
if (!allowedSortFields.includes(sortBy)) {
return res.status(400).json({ error: 'Invalid sort field' });
}
const query = `SELECT * FROM users ORDER BY ${sortBy}`;
6. Принцип наименьших привилегий
CREATE USER 'app_reader'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT ON myapp.* TO 'app_reader'@'localhost';
CREATE USER 'app_writer'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE ON myapp.* TO 'app_writer'@'localhost';
7. Полный пример защиты
const express = require('express');
const { PrismaClient } = require('@prisma/client');
const { query, body, validationResult } = require('express-validator');
const app = express();
const prisma = new PrismaClient();
const handleValidationErrors = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
};
app.get('/users/:id',
query('id').isInt().toInt(),
handleValidationErrors,
async (req, res) => {
const user = await prisma.user.findUnique({
where: { id: req.query.id },
});
res.json(user);
}
);
app.post('/users',
body('email').isEmail(),
body('password').isLength({ min: 8 }),
handleValidationErrors,
async (req, res) => {
const user = await prisma.user.create({
data: {
email: req.body.email,
password: req.body.password,
},
});
res.json(user);
}
);
Чеклист защиты
- Используй параметризованные запросы (?)
- Используй ORM вместо raw SQL
- Валидируй все входные данные
- Используй белые списки
- Применяй принцип наименьших привилегий
- Не логируй чувствительные запросы
- Используй контроль доступа
- Регулярно обновляй зависимости
- Проводи security audit
- Используй WAF в production
Типичные ошибки
const query = `SELECT * FROM users WHERE id = ${req.query.id}`;
const query = `INSERT INTO users VALUES ('${username}', '${password}');
const [rows] = await connection.execute(
'SELECT * FROM users WHERE id = ?',
[req.query.id]
);
SQL Injection остаётся одной из самых опасных уязвимостей. Ключ к защите — использование параметризованных запросов и надежных библиотек.
Похожие вопросы
- Как могут утечь все соединения из пула коннекшенов к базе данных и как это предотвратить?
- Как правильно обрабатывать uncaught exceptions и unhandled rejections в Node.js?
- В каких случаях лучше выбрать микросервисы, а в каких монолит для Node.js проекта?
- Как обеспечить failover и отказоустойчивость в Node.js приложении?
- Для чего используется оператор Infer?
- Какие знаешь инструменты масштабирования кроме worker threads?
- Как решить проблему утечки памяти на проекте?
- Какие могут быть проблемы при сортировки с параметризуемым методом?
- Как минимизировать время когда приложение не работает при деплое?
- В чем отличие Event Loop в браузере от Event Loop в Node.js?
- Как раскидывал монолит на микросервис?
- Что такое DDD?
- Для чего используется Patroni в PostgreSQL?
- Как сделать чтобы сложная математическая функция не занимала много процессов в Event Loop?
- Как сделать дамп хипа (heap dump) процесса Node.js и что с ним дальше делать?
- Всегда ли бинарный поиск при индексах?
- Что такое оптимистичная блокировка?
- Как гарантировать чтобы при работе с RabbitMQ в него не клал значение другой микросервис?
- В чем разница между Business Model и Entity Model?
- Какие проблемы возникают при использовании динамического import в Node.js?