← Назад к вопросам
Что такое SQL injection и как защитить Node.js приложение от него?
3.0 Senior🔥 261 комментариев
#Node.js и JavaScript#Базы данных и SQL#Безопасность
Комментарии (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 остаётся одной из самых опасных уязвимостей. Ключ к защите — использование параметризованных запросов и надежных библиотек.