FlawOpen

flawopen.com/SQL Injection в Java/MyBatis

MyBatis ${} и #{}: защита от SQL Injection

Справочная страница
Краткий ответ

Представьте #{value} как защищённое поле подготовленного запроса: база получает данные. ${value} копирует текст в SQL до подготовки.

Связанные значения и текст SQL

НЕБЕЗОПАСНО — текст ${}
<select id="getUser">
  SELECT * FROM users
  WHERE id = ${id}
</select>
// Raw substitution: the SQL text changes
СВЯЗАННОЕ ЗНАЧЕНИЕ — #{}
<select id="getUser">
  SELECT * FROM users
  WHERE id = #{id}
</select>
// MyBatis creates a PreparedStatement parameter

Зачем MyBatis нужны обе записи

#{} связывает значение параметром JDBC PreparedStatement. Параметр не заменяет SQL-синтаксис — имя таблицы, столбца или направление сортировки. ${} подставляет текст напрямую без экранирования. Предпочитайте статические запросы или <choose>. Иначе выбирайте идентификатор целиком из серверного списка; не интерполируйте произвольный текст запроса.

Когда нужны динамические идентификаторы

Разрешайте полный SQL-идентификатор или фрагмент

Параметр не заменяет идентификатор. Для сортировки сопоставляйте выбор фиксированному SQL в коде сервера (или используйте <choose>). Не передавайте столбец, таблицу или ASC/DESC клиента прямо в ${}. Экранирование не делает произвольный фрагмент безопасным.

Проверка MyBatis mapper

rg -n -F '${' --glob '*.xml' --glob '*.java' .
Проверьте XML и аннотации, проследите источник значения. Используйте #{} для значений; ${} — только для значений из конечного серверного списка. Поиск находит синтаксис, но не всё косвенное формирование SQL.

Частые вопросы

Это относится к mapper с аннотациями?

Да. Правила те же. ${column} в @Select вставляет текст напрямую; связывайте значения через #{value}, идентификаторы разрешайте списком.

Достаточно ли поиска ${}, чтобы доказать безопасность?

Нет. Проверьте совпадения; SQL может собираться в другом месте. Добавьте проверки XML и аннотаций и тесты на фиксированные варианты сортировки.

Источники

См. также SQL-инъекции (CWE-89): как они работают и как их предотвратить в любом языке — flawopen.com MySQLi и PDO: безопасные подготовленные запросы Защищает ли NHibernate от SQL-инъекций? NoSQL-инъекция в MongoDB: безопасные фильтры SQL Injection при числовых ID: риск? Что такое параметризованный запрос? Защищает ли Prisma $queryRaw от SQL-инъекций?