Как Mybatis реализует предотвращение SQL-инъекций

Java

Фреймворк 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, если у вас есть какие-либо вопросы, вы можете связаться по электронной почте.