简单了解Mybatis如何实现SQL防注入

前端之家收集整理的这篇文章主要介绍了简单了解Mybatis如何实现SQL防注入前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这篇文章主要介绍了简单了解Mybatis如何实现sql防注入,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

Mybatis这个框架在日常开发中用的很多,比如面试中经常有一个问题:$和#的区别,它们的区别是使用#可以防止sql注入,今天就来看一下它是如何实现sql注入的。

什么是sql注入

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

如果正常操作,传入一个正常的id,比如说2,那么这条语句变成select * from user where id =2。这条语句是可以正常运行并且符合我们预期的。

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

Mybatis如何防止sql注入

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

  1. <select id="safeSelect" resultMap="testUser">
  2. SELECT * FROM user where id = #{id}
  3. </select>

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

  1. <select id="unsafeSelect" resultMap="testUser">
  2. select * from user where id = ${id}
  3. </select>

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

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

弃用$可以吗

我们使用#也能完成$的作用,并且使用$还有危险,那么我们以后不使用$不就行了吗。

并不是,它只是在我们这种场景下会有问题,但是在有一些动态查询的场景中还是有不可代替的作用的,比如,动态修改表名select * from ${table} where id = #{id}。我们就可以在返回信息一致的情况下进行动态的更改查询的表,这也是mybatis动态强大的地方。

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

其实Mybatis也是通过jdbc来进行数据库连接的,如果我们看一下jdbc的使用,就可以得到这个原因。

#使用了PreparedStatement来进行预处理,然后通过set的方式对占位符进行设置,而$则是通过Statement直接进行查询,当有参数时直接拼接进行查询

所以说我们可以使用jdbc来实现sql注入。

看一下这两个的代码:

  1. public static void statement(Connection connection) {
  2. System.out.println("statement-----");
  3. String selectsql = "select * from user";
  4. // 相当于mybatis中使用$,拿到参数后直接拼接
  5. String unsafesql = "select * from user where id = '' or 1=1;";
  6. Statement statement = null;
  7. try {
  8. statement = connection.createStatement();
  9. } catch (sqlException e) {
  10. e.printStackTrace();
  11. }
  12. try {
  13. ResultSet resultSet = statement.executeQuery(selectsql);
  14. print(resultSet);
  15. } catch (sqlException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println("---****---");
  19. try {
  20. ResultSet resultSet = statement.executeQuery(unsafesql);
  21. print(resultSet);
  22. } catch (sqlException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26.  
  27. public static void preparedStatement(Connection connection) {
  28. System.out.println("preparedStatement-----");
  29. String selectsql = "select * from user;";
  30. //相当于mybatis中的#,先对要执行的sql进行预处理,设置占位符,然后设置参数
  31. String safesql = "select * from user where id =?;";
  32. PreparedStatement preparedStatement = null;
  33. try {
  34. preparedStatement = connection.prepareStatement(selectsql);
  35. ResultSet resultSet = preparedStatement.executeQuery();
  36. print(resultSet);
  37. } catch (sqlException e) {
  38. e.printStackTrace();
  39. }
  40. System.out.println("---****---");
  41. try {
  42. preparedStatement = connection.prepareStatement(safesql);
  43. preparedStatement.setString(1," '' or 1 = 1 ");
  44. ResultSet resultSet = preparedStatement.executeQuery();
  45. print(resultSet);
  46. } catch (sqlException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50.  
  51. public static void print(ResultSet resultSet) throws sqlException {
  52. while (resultSet.next()) {
  53. System.out.print(resultSet.getString(1) + ",");
  54. System.out.print(resultSet.getString("name") + ",");
  55. System.out.println(resultSet.getString(3));
  56. }
  57. }

总结

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

猜你在找的Java相关文章