sql注入及mybatis防止sql注入(六)

发布时间 2023-12-27 16:57:30作者: 慎终若始

前言

1、回顾什么是sql注入

2、mybatis如何解决sql注入

一、sql注入及mybatis防止sql注入

1.1Sql 注入产生原因及威胁

  当我们访问动态网页时, Web 服务器会向数据访问层发起 Sql 查询请求,如果权限验证通过就会执行 Sql 语句。这种网站内部直接发送的Sql请求一般不会有危险,但实际情况是很多时候需要结合用

户的输入数据动态构造 Sql 语句,如果用户输入的数据被构造成恶意 Sql 代码,Web 应用又未对动态构造的 Sql 语句使用的参数进行审查,则会带来意想不到的危险。

  Sql 注入带来的威胁主要有如下几点:

  • 猜解后台数据库,这是利用最多的方式,盗取网站的敏感信息。
  • 绕过认证,列如绕过验证登录网站后台。
  • 注入可以借助数据库的存储过程进行提权等操作。

1.2Mybatis防止sql注入

下面是MyBatis一个Dao配置

<select id="findRank" parameterType ="String" resultType="String">
    SELECT u.name FROM UserInfo u
        where 1=1 and u.UserID=#{userID} ;    
</select>

打印出执行的SQL语句

 SELECT u.name FROM UserInfo u where 1=1 and u.UserID=?     

这是因为MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这

样的方式就很好地避免了SQL注入的问题。

  • 底层实现原理

  MyBatis是如何做到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这

种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。PreparedStatement只能用来为参数(如参数值)设置动态参数,即用?占位,不可用于表名、字段名等。

  话说回来,是否我们使用MyBatis就一定可以防止SQL注入呢?当然不是,请看下面的代码:

<select id="findRank" parameterType ="String" resultType="String">
    SELECT u.name FROM UserInfo u
        where 1=1
        and u.UserID=${userID} ;   
</select>

假设userID=1,将SQL打印出来是这样的:

 SELECT u.name FROM UserInfo u where 1=1 and u.UserID=1

显然${}这种方式直接参与sql编译,将传入的参数直接显示生成在sql中,不能避免注入攻击。

1.3mybatis${ } 和 #{ }区别

  • #方式能够很大程度防止sql注入。
  • $方式无法防止Sql注入。
  • $方式一般用于传入数据库对象,例如传入表名。

${xxx}

  • 缺点: 直接参与SQL编译,不能避免注入攻击。
  • 优点:及到动态表名和列名时,只能使用“${xxx}”这样的参数格式
  • 注意:这样的参数需要我们在代码中手工进行处理来防止注入。
  • ${}将传入的参数直接显示生成在sql中,不会添加引号

#{xxx}

  • 相当于JDBC中的PreparedStatement
  • #{}将传入的参数当成一个字符串,会给传入的参数加一个双引号
  • 优点:#{}是经过预编译的,是安全的;

参看链接:https://blog.csdn.net/cristianoxm/article/details/123726070