sql注入
通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
危害:数据库信息泄露
恶意字符:1 or 1='1'等
案例:
package com.zhiwei.database;
import java.sql.*;
public class PrepareStatementTest {
public static void main(String[] args) {
PreparedStatement ps =null;
ResultSet rs=null;
Connection ct=null;
try {
Class.forName("com.mysql.jdbc.Driver");
ct = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test","squirrel","xiaoyang");
ps=ct.prepareStatement("select *from user where name='zhangsan' and '1' or 1='1'");
rs=ps.executeQuery();
while(rs.next()){
int id =rs.getInt(1);
String name = rs.getString(2);
String passwd = rs.getString(3);
int age=rs.getInt(4);
String sex=rs.getString(5);
System.out.println(id+"--"+name+"--"+passwd+"--"+age+"--"+sex);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
if(rs!=null){
rs.close();
}if(ps!=null){
ps.close();
}if(ct!=null){
ct.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
控制台日志:
1--zhangsan--zhangsan--10--F
2--lisi--lisi--20--M
3--wangwu--wangwu--15--M
4--maliu--maliu--13--F
5--tianqi--tianqi--18--M
6--maba--maba--19--F
22--BBBB--BBBB--16--M
数据库记录:
结果:
sql语句没有查出我们想要的数据记录,而是将所有的表的记录都查询出来了,造成数据泄露(典型的sql注入漏洞)
分析:
select *from user where name='zhangsan' and '1' or 1='1'
sql语句中and的优先级高于or的优先级,因此 select *from user where name='zhangsan' and '1' or 1='1' 等价于: select *from user where (name='zhangsan' and '1') or 1='1' 因name='zhangsan' and '1' or 1='1'的最终结果都是为真,where条件就失去作用,整条sql的功能等价于:select *from user
sql优化语句:
select *from user where name='zhangsan' and ('1' or 1='1')
分析 :
将恶意sql字符隔开,根据()的优先级大于and,因此整个sql语句的判断条件就变成name='zhangsan'和('1' or 1='1'),而('1' or 1='1')永久为真,因此整条语句就实现了对name的过滤作用,恶意sql则变得多余,但这样的sql并没有实际的使用价值
sql注入的解决方案
- 使用PrepareStatement类的set方法,它在sql预编译的时候对sql语句进行转义,PrepareState过滤特定的字符将“干净”的二进制文件提交给数据库,因而就达不到欺骗数据库的效果 ps=ct.prepareStatement("select *from user where name=?"); ps.setString(1, "zhangsan and 1 or 1='1'"); rs=ps.executeQuery();
- web项目中一般使用过滤器或者拦截器去过滤页面表单传过来的字符,拼接"干净"的sql语句再提交数据库执行
注意:Mybatis中 $ 只是简单的变量替换存在sql注入风向, # 会将sql语句预编译,防止sql注入