SQL注入攻击产生的原因: 由于后台执行的SQL语句是拼接而来的:
select * from user where username='"+user+"' and password='"+pwd+"'
其中的参数是用户提交过来的,如果用户在提交参数时,在参数中掺杂了一些SQL关键字(比如or)或者特殊符号(#、-- 、’ 等),就可能会导致SQL语句语义的变化,从而执行一些意外的操作(用户名或密码不正确也能登录成功)!
例如:
请登录:
请输入用户名:
张飞'#'
请输入密码:
select * from user where username='张飞'#'' and password=''
恭喜您登录成功了!
或者:
请登录:
请输入用户名:
张飞' or '1=1
请输入密码:
select * from user where username='张飞' or '1=1' and password=''
恭喜您登录成功了!
或者:
请登录:
请输入用户名:
请输入密码:
' or '2=2
select * from user where username='' and password='' or '2=2'
恭喜您登录成功了!
防止SQL注入攻击
(1)使用正则表达式对用户提交的参数进行校验。如果参数中有(# – ’ or等)这些符号就直接结束程序,通知用户输入的参数不合法
(2)使用PreparedStatement对象来替代Statement对象。
下面通过第二种方式解决SQL注入攻击:添加loginByPreparedSatement方法,在方法中,使用PreparedStatement来代替Statement作为传输器对象使用,代码示例:
/**
* 根据用户名和密码查询用户信息
* @param user 用户名
* @param pwd 密码
*/
private static void login(String user, String pwd) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1.注册驱动并获取连接
conn = JdbcUtil.getConn();
//2.获取传输器,执行sql并返回执行结果
String sql = "select * from user where username=? and password=?";
ps = conn.prepareStatement( sql );
//设置SQL语句中的参数
ps.setString( 1 , user );
ps.setString( 2 , pwd );
//执行SQL语句
rs = ps.executeQuery();//这里不要再传输SQL语句
//3.处理结果
if( rs.next() ) { //有数据 -- 用户名密码都正确
System.out.println("恭喜您登录成功!");
}else { //没数据 -- 用户名或密码不正确
System.out.println("登录失败, 用户名或密码不正确!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//4.释放资源
JdbcUtil.close(conn, ps, rs);
}
}
PreparedStatement对象是如何防止SQL注入攻击的:
使用PreparedStatement对象是先将SQL语句的骨架发送给服务器编译并确定下来,编译之后,SQL语句的骨架和语义就不会再被改变了,再将SQL语句中的参数发送给服务器,即使参数中再包含SQL关键字或者特殊符号,也不会导致SQL语句的骨架或语义被改变,只会被当作普通的文本来处理!
即:预编译。
其他方法:
1)不使用SQL,考虑NoSQL
2)JSP中调用该函数检查是否包函非法字符或JSP页面判断代码。JSP参考JSP使用过滤器防止SQL注入