Ответ
Основной и самый надежный метод защиты — использование параметризованных запросов (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.
Ответ 18+ 🔞
Да что ж такое-то, блядь! Смотри, тут люди как будто с луны свалились — до сих пор строки конкатенируют, чтобы SQL-запросы собирать. Ёпта, ну это же пиздец, товарищи! Это как на машине без тормозов с горки ехать и надеяться, что в кусты мягко припаркуешься. Овердохуища уязвимостей открывается!
Так, слушай сюда, главное правило, которое надо на лбу вытатуировать: используй параметризованные запросы (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. Другие полезные штуки, чтобы спать ещё крепче:
- Принцип наименьших привилегий: Зачем твоему приложению в базе права на
DROP TABLE? Да низачем! Дай ему толькоSELECT,INSERT,UPDATE,DELETEна нужные таблицы и всё. Пусть сидит в своей песочнице. - Валидация данных на входе: Это, конечно, не панацея от SQL-инъекций, но отсеять откровенный бред — всегда полезно. Используй Joi, Zod или что там у тебя. Чисто для порядка.
- Хранимые процедуры: Ну, теоретически, если их с параметрами вызывать, то тоже вариант. Но в мире Node.js это как-то не очень популярно, честно говоря.
- Апдейти зависимости: Забыл обновить драйвер или ORM, а там дыра? Сам дурак, блядь. Следи за этим.
Итог, который надо выжечь в мозгу: Никогда, слышишь, НИКОГДА не доверяй тому, что пользователь ввёл в твою форму. И уж тем более не лепи из этого SQL-запросы, склеивая строки. Это уровень "Hello, World!" для начинающих пентестеров. Используй те инструменты параметризации, которые тебе твой драйвер или ORM предоставляет. И будет тебе счастье, а не хиросима в базе данных.