SQL-инъекция — это простой вектор атаки, который до сих пор очень распространён. Причина этого не в том, что нет патча для глупости. Почему вы так говорите? Давайте возьмём JAVA в качестве примера:
Предположим, что такая таблица существует в базе данных:
Затем используйте таблицу действий JDBC:
Вышеуказанный код часто используется некоторыми разработчиками. Представьте ситуацию, где входящий параметр userId — «3; пользователь таблицы выброса; Выполняемый SQL-оператор выглядит следующим образом:
После компиляции и выполнения базы данных пользовательская таблица удаляется. Вуаля, срабатывает простая атака SQL-инъекцией! Это связано с тем, что вышеуказанный код не соответствует спецификациям программирования.
Когда мы программируем по спецификации, SQL-инъекции отсутствуют. Это тоже такПервый способ избежать SQL-инъекций: предварительно скомпилированные операторы, код следующий:
Почему в вышеуказанном коде нет SQL-инъекции? Поскольку используется заранее скомпилированный оператор, скомпилированный оператор установит «select name from user, где id=?» Оператор компилируется заранее, так что его нужно заменять на входящие параметры только при выполнении? Временные варианты — это нормально. В первом несовместимом случае программа пишет SQL-оператор, а затем компилирует его с содержимым, переданным пользователем, что и является проблемой.
Помимо использования заранее скомпилированных операторов, есть и второй вариантСпособы избежать атак SQL-инъекций: Хранимые процедуры。 Сохранённая процедура — это набор SQL-операторов, которые выполняют определённую функцию, скомпилированные и хранящиеся в базе данных, и пользователь может выполнить её, вызвав сохранённую процедуру и предоставив параметр (если у хранимой процедуры есть параметры), что также позволяет избежать атак SQL-инъекций
Соответствующая сохранённая процедура в приведённом выше коде выглядит следующим образом:
Конечно, пользователи также могут проверять символы на фронтенде, что также помогает избежать SQL-инъекции: например, для параметра userId выше пользователь проверит точку с запятой, и появляется ошибка. Однако самая фундаментальная причина заключается в том, что SQL-инъекции существуют потому, что приложения не используют наименьшие привилегии при доступе к базам данных. Похоже, что все используют root-аккаунт для доступа к базе данных.
Так как же MyBatis избегает атак с помощью SQL-инъекций? Или возьмём пользователя таблицы выше в качестве примера: Допустим, файл mapper выглядит так:
Соответствующие java-файлы:
Вы можете увидеть, что входный параметр — userId типа String, при передаче userId="34; пользователь таблицы выброса; После этого в распечатанном заявлении говорится:
Независимо от введённого userID, его sql-оператор выглядит так. Это связано с тем, что mybatis использует заранее скомпилированные операторы в базовой реализации. Когда база данных выполняет этот оператор, она напрямую использует заранее скомпилированный оператор, а затем заменяет заполнитель на проходящий userId? Просто беги. Сначала заменить временные варианты? Процесс компиляции выполняется, поэтому нет возможности для выживания SQL-инъекций.
Так как же MyBatis выполняет предкомпиляцию SQL? На самом деле, класс PreparedStatement используется внизу фреймворка. Класс PreparedStaement не только избегает SQL-инъекций, но и экономит время компиляции (N-1), когда один и тот же SQL-оператор выполняется N раз, тем самым повышая эффективность.
Если изменить вышеуказанное утверждение на:
Когда мы вводим userId="34; пользователь таблицы выброса; После этого в распечатанном заявлении говорится:
В данный момент mybatis не использует предварительно скомпилированные операторы, он сначала сшивает строки, а затем выполняет компиляцию — именно так вступает в действие SQL-инъекция.
Поэтому при написании операторов отображения mybatis старайтесь использовать формат "#{xxx}". Если нужно использовать параметры вроде "${xxx}", их нужно вручную фильтровать, чтобы предотвратить атаки SQL-инъекций.
|