Ответ
Основной и самый надежный метод защиты — использование параметризованных запросов (Prepared Statements). При таком подходе данные пользователя передаются отдельно от кода запроса, и СУБД сама корректно их экранирует.
1. Использование драйверов и ORM с поддержкой параметризации:
-
Нативный драйвер
mysql2/pg(PostgreSQL):// УЯЗВИМЫЙ КОД (конкатенация строк) const query = `SELECT * FROM users WHERE email = '${email}'`; connection.query(query); // Если email = "' OR '1'='1", получим инъекцию // ЗАЩИЩЕННЫЙ КОД (параметризованный запрос) const safeQuery = 'SELECT * FROM users WHERE email = ?'; connection.execute(safeQuery, [email]); // Драйвер корректно подставит значение -
ORM Sequelize:
// Sequelize автоматически использует параметризованные запросы const users = await User.findAll({ where: { email: req.body.email // Безопасно! } }); -
Query Builder Knex.js:
knex('users').where('email', '=', email).select('*'); // Безопасно
2. Дополнительные меры защиты:
- Принцип наименьших привилегий: У учетной записи приложения в БД должны быть только необходимые права (обычно
SELECT,INSERT,UPDATE,DELETEна конкретные таблицы, но неDROP,CREATEи т.д.). - Валидация и санация входных данных: Хотя это не заменяет параметризацию, строгая валидация (например, с помощью Joi или Zod) на уровне API отсекает заведомо некорректные данные.
- Хранимые процедуры: Могут быть безопасны, если вызываются с параметрами, но в экосистеме Node.js используются реже.
- Регулярное обновление зависимостей: Уязвимости могут быть в самих ORM или драйверах.
Главное правило: Никогда не доверяйте пользовательскому вводу и никогда не склеивайте SQL-запросы строковой конкатенацией или шаблонными литералами. Всегда используйте механизмы параметризации, предоставляемые вашим драйвером или ORM.