天天看点

以mybatis为例浅聊SQL注入

以mybatis为例浅聊SQL注入

以用户登录为例,传统代码为一个form表单,输入username和password去数据库发送sql检索,用的是字符串拼接${}。

select * from t_user where password = ‘ password′andusername=′ {username}’

如果页面输入

zhangsan

1111’ or ‘1 = 1

则sql语句为

select * from t_user where password = ‘1111’ or ‘1 = 1’and username = ‘zhangsan’

此时无论用户名为zhangsan的该用户密码为何值,均能查询出一条记录。

而用了预编译的#{}占位符后

代码为

select * from t_user where password = #{password} and username = #{username}

即mybatis发送给数据库的sql为

select * from t_user where password = ? and username = ?

在数据库端便会对该sql进行编译,如果下次有该查询时,mabatis会发送select * from t_user where password = #{password} and username = #{username}作为“KEY”,页面传入的参数作为“VALUE”

去数据库查询,预编译的方式使得发送至数据库的值为sql “KEY” 和 参数 “VALUE”,

数据库根据KEY找到编译好的sql,将参数注入进行查询

如果页面输入

zhangsan

1111’ or ‘1 = 1

则sql语句为

select * from t_user where password = ‘1111’ or ‘1 = 1’and username = ‘zhangsan’

看到这也许会有疑问,这和传统的字符串拼接,得到的sql还是一样的啊?

其实并不是,sql只是数据库端给我们看的一段字符串,真正的查询方式,

传统字符串拼接查询,传入数据库的是一个参数,为在程序端拼接好的sql,直接去数据库执行。

而预编译方式,传入数据库的是两个参数,一个是select * from t_user where password = ? and username = ?语句,一个是值。如果数据库里没该条SQL就会编译好缓存,如果缓存有的话,直接类似“函数接收参数”的方式去执行sql

,那么,数据库里是不会有任何一条记录的密码为1111’ or ‘1 = 1,就不会返回记录。从某种意义上来说防止了SQL注入。