Возможна ли SQL-инъекция через literal() в ORM-запросе?
ORM-запрос (Sequelize) смешивает сырой фрагмент literal() с replacements. Решите, возможна ли SQL-инъекция, и объясните почему.
Ограничения:
firstNameконтролируется атакующим и доходит до текстаliteral()- считайте, что версия ORM устаревшая, с известными багами разбора
User.findAll({
where: or(literal(`soundex("firstName") = soundex(:firstName)`),
{ lastName }),
replacements: { firstName },
});
Определите причину.
Да — literal() это лазейка для сырого SQL; ORM НЕ параметризует текст внутри него. Подстановка :firstName — это лишь строковая замена, и на устаревшей версии особый firstName (и lastName, равный :firstName) выходит из literal и внедряет SQL. Фикс: никогда не помещать пользовательский ввод рядом с literal(); полагаться на параметризованные операторы where ORM и обновить библиотеку.
- ✗Думать, что ORM параметризует сырой SQL внутри
literal() - ✗Считать, что наличие
replacementsделает весь запрос безопасным - ✗Принимать инъекцию через literal за баг производительности
- →Почему
replacementsне защищает текст, переданный вliteral()? - →Когда вообще оправдано использовать
literal()в ORM-запросе?
Уязвимость
literal() — это сырой SQL, который ORM вставляет как есть. Параметризация (replacements) работает только для биндов ORM, но НЕ защищает текст внутри literal():
where: or(literal(`soundex("firstName") = soundex(:firstName)`), { lastName })
На устаревшей версии Sequelize подстановка :firstName — строковая замена. Пейлоад:
{"firstName":"OR true; DROP TABLE users;","lastName":":firstName"}
выходит из literal → SQL-инъекция.
Исправление
User.findAll({ where: { firstName, lastName } });
✅ Параметризованные операторы where ORM экранируют ввод. ⚠️ Не помещайте пользовательский ввод рядом с literal(); обновите библиотеку.