Фреймворк Mybatis часто используется в повседневной разработке, например, на собеседованиях часто задают вопрос:$
и#
Разница между ними заключается в использовании#
Может предотвратить SQL-инъекцию, давайте посмотрим, как это реализует SQL-инъекцию сегодня.
Что такое SQL-инъекция
Прежде чем обсуждать, как это реализовать, давайте сначала разберемся, что такое SQL-инъекция.У нас есть простая операция запроса: запрос информации о пользователе на основе идентификатора. Его оператор sql должен быть таким:select * from user where id =
. Мы заполняем id для запроса в соответствии с входящими условиями.
Если вы работаете в обычном режиме и передаете обычный идентификатор, скажем, 2, то это утверждение становитсяselect * from user where id =2
. Это утверждение работает и работает так, как мы ожидаем.
Но если переданный параметр становится '' or 1=1
, то выражение становитсяselect * from user where id = '' or 1=1
. Давайте подумаем о результате выполнения этого оператора. Он будет запрашивать все данные в нашей пользовательской таблице, очевидно, это большая ошибка. Это SQL-инъекция.
Как Mybatis предотвращает SQL-инъекцию
Как упоминалось в начале, вы можете использовать#
Чтобы предотвратить SQL-инъекцию, он написан следующим образом:
<select id="safeSelect" resultMap="testUser">
SELECT * FROM user where id = #{id}
</select>
В мибати, еще есть способ написания$
Это выглядит следующим образом:
<select id="unsafeSelect" resultMap="testUser">
select * from user where id = ${id}
</select>
Когда мы продолжим вызывать эти два метода извне, мы обнаружим, что если переданы безопасные параметры, результаты двух одинаковы.Если переданы небезопасные параметры, используется первый метод.#
Запрос метода не дает результатов (select * from user where id = '' or 1=1
), но этот параметр используется во втором$
Вы получите все результаты ниже.
И если мы напечатаем sql, вы найдете добавленные#
, sql, выполненный для базы данных:select * from user where id = ' '' or 1=1 '
, он добавит слой кавычек вокруг наших параметров и использует$
Когда он выполняется, sqlselect * from user where id = '' or 1=1
.
устарел$
это нормально
Мы используем#
также можно сделать$
функционировать и использовать$
Так же есть опасность, потом не будем использовать$
Разве это не сработает?
Нет, это только проблема в нашем сценарии, но она по-прежнему играет незаменимую роль в некоторых сценариях динамических запросов, например, при динамическом изменении имени таблицы.select * from ${table} where id = #{id}
. Мы можем динамически изменять запрошенную таблицу при условии, что возвращаемая информация непротиворечива, что также является динамической и мощной частью mybatis.
Как реализовать SQL-инъекцию без Mybatis
На самом деле, Mybatis также использует jdbc для подключения к базе данных, если мы посмотрим на использование jdbc, мы сможем понять эту причину.
#
использовалPreparedStatement
предварительно обработать, а затем установить заполнители с помощью набора и$
черезStatement
Запрос напрямую и прямое соединение с запросом при наличии параметров.
Таким образом, мы можем использовать jdbc для внедрения SQL.
Посмотрите на код:
public static void statement(Connection connection) {
System.out.println("statement-----");
String selectSql = "select * from user";
// 相当于mybatis中使用$,拿到参数后直接拼接
String unsafeSql = "select * from user where id = '' or 1=1;";
Statement statement = null;
try {
statement = connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
try {
ResultSet resultSet = statement.executeQuery(selectSql);
print(resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("---****---");
try {
ResultSet resultSet = statement.executeQuery(unsafeSql);
print(resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void preparedStatement(Connection connection) {
System.out.println("preparedStatement-----");
String selectSql = "select * from user;";
//相当于mybatis中的#,先对要执行的sql进行预处理,设置占位符,然后设置参数
String safeSql = "select * from user where id =?;";
PreparedStatement preparedStatement = null;
try {
preparedStatement = connection.prepareStatement(selectSql);
ResultSet resultSet = preparedStatement.executeQuery();
print(resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("---****---");
try {
preparedStatement = connection.prepareStatement(safeSql);
preparedStatement.setString(1," '' or 1 = 1 ");
ResultSet resultSet = preparedStatement.executeQuery();
print(resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void print(ResultSet resultSet) throws SQLException {
while (resultSet.next()) {
System.out.print(resultSet.getString(1) + ", ");
System.out.print(resultSet.getString("name") + ", ");
System.out.println(resultSet.getString(3));
}
}
Суммировать
- Используется в Мибатисе
#
Может предотвратить внедрение SQL,$
не предотвращает внедрение SQL - Принцип Mybatis для внедрения SQL-инъекций заключается в вызове jdbc в
PreparedStatement
для предварительной обработки.
Эта статья опубликована в блогеOpenWriteвыпуск!
Электронная почта блогера: liunaijie1996@163.com, если у вас есть какие-либо вопросы, вы можете связаться по электронной почте.