java防注入原理和sql运行过程
谈及java防注入就要谈及sql运行过程,只有理解了sql运行过程,才能理解预编译,才能深入了解java防注入的实现原理
1 sql注入
sql注入,简单来说就是用户在前端web页面输入恶意的sql语句(拼接的sql语句)来欺骗后端服务器去执行恶意的sql代码,从而导致数据库数据泄露或者遭受攻击。
2 解决sql注入方法
2.1 那么如何解决sql注入?
在JDBC进行连接时使用PreparedStatement类去代替Statement,或者传入的条件参数完全不使用String字符串,同样地,在用mybatis时,则尽量使用#{param}占位符的方式去避免sql注入(${param}可以通过拼接参数实现sql注入)。
2.2 防止sql注入原理
这两个不同环境下解决sql注入实际原理是一致的。当使用PreparedStatement去写sql语句时,程序会对该条sql首先进行预编译,然后会将传入的字符串参数以字符串的形式去处理,即会在参数的两边自动加上单引号(’param’),而Statement则是直接简单粗暴地通过人工的字符串拼接的方式去写sql,那这样就很容易被sql注入。这里就需要理解sql运行过程(后面会讲到)
那么,如果PreparedStatement只是仅仅简单地通过把字符串参数两边加上引号的方式去处理,一样也很容易被sql注入,下面举个例子带着大家简单了解下sql注入。
创建user表(id,name,class);
create table user
(
id int4 PRIMARY KEY,
name VARCHAR(20) not null,
class VARCHAR(20)
)
里面有如下几条数据:
INSERT INTO `user` VALUES ('1', 'Tom', '1班');
INSERT INTO `user` VALUES ('2', 'Jeery', '2班');
这里我们使用mybatis的$ {param} 和 #{param} 两个不同的占位符来作为示例解释 Statement 和 PreparedStatement (mybatis和jdbc的低层原理是一样的)。不了解mybatis的读者可以暂时放下这个疑问,或者搜索查看下${}和#{}的区别。
首先{}是不能防止sql注入的,它能够通过字符串拼接的形式来任意摆弄你的sql语句,而#{}则可以很大程度上地防止sql注入,下面是关于这个的一条sql:
<mapper namespace="com.sky.dao.UserMapper">
<select id="query" parameterType="com.sky.model.User" resultType="com.sky.model.User">
select * from user where name = '${name}'
</select>
</mapper>
- 前端页面的简略的代码:
<form action="<%=basePath%>query" method="get">
<input type="input" placeholder="请输入姓名" name="name"/><input type="submit" value="查询"/>
</form>
前端页面通过form表单的形式输入查询条件并调用后端sql。如果使用的是${param}占位符
select * from user where name = ${name}
当在前端传入参数为:Tom,则对应sql为:select * from user where name = ‘Tom’;这时只显示Tom的数据。
但是,如果其传入参数为:‘Tom’ or 1=’1;则传到后台之后其对应的sql就变为:select * from user where name = ‘Tom’ or 1=’1’;此时得到的为全表数据,这个就有了很大的问题。
将mybatis中的sql语句改为:select * from user where name = #{name}<