Mybatis是如何实现SQL防注入的

Mybatis这个框架在平常开发中用的不少,好比面试中常常有一个问题:$#的区别,它们的区别是使用#能够防止SQL注入,今天就来看一下它是如何实现SQL注入的。面试

什么是SQL注入

在讨论怎么实现以前,首先了解一下什么是SQL注入,咱们有一个简单的查询操做:根据id查询一个用户信息。它的sql语句应该是这样:select * from user where id = 。咱们根据传入条件填入id进行查询。sql

若是正常操做,传入一个正常的id,好比说2,那么这条语句变成select * from user where id =2。这条语句是能够正常运行而且符合咱们预期的。数据库

可是若是传入的参数变成 '' or 1=1,这时这条语句变成select * from user where id = '' or 1=1。让咱们想一下这条语句的执行结果会是怎么?它会将咱们用户表中全部的数据查询出来,显然这是一个大的错误。这就是SQL注入。安全

Mybatis如何防止SQL注入

在开头讲过,可使用#来防止SQL注入,它的写法以下:mybatis

<select id="safeSelect" resultMap="testUser">
   SELECT * FROM user where id = #{id}
</select>复制代码

在mybatis中查询还有一个写法是使用$,它的写法以下:框架

<select id="unsafeSelect" resultMap="testUser">
   select * from user where id = ${id}
</select>复制代码

当咱们在外部对这两个方法继续调用时,发现若是传入安全的参数时,二者结果并没有不一样,若是传入不安全的参数时,第一种使用#的方法查询不到结果(select * from user where id = '' or 1=1),但这个参数在第二种也就是$下会获得所有的结果。spa

而且若是咱们将sql进行打印,会发现添加#时,向数据库执行的sql为:select * from user where id = ' '' or 1=1 ',它会在咱们的参数外再加一层引号,在使用$时,它的执行sql是select * from user where id = '' or 1=1code

弃用$能够吗

咱们使用#也能完成$的做用,而且使用$还有危险,那么咱们之后不使用$不就好了吗。开发

并非,它只是在咱们这种场景下会有问题,可是在有一些动态查询的场景中仍是有不可代替的做用的,好比,动态修改表名select * from ${table} where id = #{id}。咱们就能够在返回信息一致的状况下进行动态的更改查询的表,这也是mybatis动态强大的地方。get

如何实现SQL注入的,不用Mybatis怎么实现

其实Mybatis也是经过jdbc来进行数据库链接的,若是咱们看一下jdbc的使用,就能够获得这个缘由。

#使用了PreparedStatement来进行预处理,而后经过set的方式对占位符进行设置,而$则是经过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));
  }
}复制代码

总结

  • Mybatis中使用#能够防止SQL注入,$并不能防止SQL注入
  • Mybatis实现SQL注入的原理是调用了jdbc中的PreparedStatement来进行预处理。

本文由博客一文多发平台 OpenWrite 发布!博主邮箱:liunaijie1996@163.com,有问题能够邮箱交流。

相关文章
相关标签/搜索