Как защититься от SQL инъекции
Что проверяют
Понимаете ли вы, что защита строится на разделении кода запроса и данных, а не на фильтрации ввода. Для Node.js это ещё и проверка, знаете ли вы, где конкретные драйверы и ORM оставляют лазейки. Следом обычно просят: «А если нужно подставить имя колонки для сортировки?»
Как отвечать
Основа: параметризованные запросы, где значения уходят в базу отдельно от текста SQL и не могут стать его частью.
pg:pool.query('SELECT * FROM users WHERE email = $1', [email]);mysql2:connection.execute(sql, [id])использует серверные prepared statements, аqueryс?экранирует значения на стороне клиента. Несколько выражений в одном вызове по умолчанию запрещены, иmultipleStatementsлучше не включать;- Prisma:
$queryRawв виде tagged template параметризует подстановки сам, а$queryRawUnsafeсо склейкой строк снова открывает инъекцию; - Knex, Sequelize, TypeORM: безопасны, пока вы пользуетесь билдером. В сырых фрагментах (
whereRaw,sequelize.query,createQueryBuilder().where(...)) значения передаются через?,replacementsилиbind, именованные параметры:id, а не через шаблонную строку.
Идентификаторы (имя таблицы, колонки, направление сортировки) параметром передать нельзя. Их проверяют по белому списку: const col = allowed.includes(sort) ? sort : 'created_at'.
Второй слой: пользователь базы с минимальными правами, без DDL и доступа к чужим схемам; валидация входа через zod или joi; ошибки базы не отдаются клиенту. И отдельно для Node: с MongoDB опасна уже NoSQL-инъекция, когда из JSON приходит { "$ne": null } вместо строки.
Где спотыкаются
Пишут запрос через шаблонную строку: ` pool.query(... WHERE id = ${id}) `. Выглядит аккуратно, но это та же конкатенация.
Считают, что ORM защищает всегда. Сырые методы вроде whereRaw и sequelize.query с подстановкой из req.query дают инъекцию и в ORM.
Надеются на экранирование и регулярные выражения вместо параметров. Экранирование зависит от кодировки и диалекта, и рано или поздно находится обход.