关于sql预编译使用
未进行预编译的代码
public boolean findByPassword(String username, String password) {
Connection coon = null;
Statement state = null;
ResultSet rs = null;
try {
coon = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8","root","");
state = coon.createStatement();
//insert into xzk_user values('"+username+"','"+password+"') :字符串的定义格式 字符串的表现格式 字符串需要用引号引住
rs =state.executeQuery("select * from xzk_user where username= '"+username+"'and password='"+password+"'");
//游标向下移动 有数据就能移动成功
return rs.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
state.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
coon.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
该user表中默认数据
出现的结果
然而此时却能用不存在的账号和该密码登陆进去,是不是顿时这个人都感觉不太好
这时候对其采用预编译的方式进行处理
public boolean findByPassword(String username, String password) {
Connection coon = null;
PreparedStatement state = null;
ResultSet rs = null;
try {
coon = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8","root","");
//参数: 预编译的SQL语句,参数部分使用?替代
state = coon.prepareStatement("select * from xzk_user where username=? and password=?");
//向预编译的执行环境中,加入参数的内容
state.setString(1,username);
state.setString(2,password);
//执行
rs = state.executeQuery();
return rs.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
state.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
coon.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
再次进行登陆
这是为什么呢?
因为在输入密码为 1’ or ‘1’='1 时,对于第一种未预编译的Statement而言,是用"++"的方式来字符串拼接的,那么外部就可以使用"+OR+"这样拼接方式来对SQL进行注入,只要 or 两边只要有一边是绝对成立的时候,就可以将代码运行到下一步去,从而跳过登陆验证的限制,这对于数据安全而言是及其的难受。
对于第二种进行预编译的 prepareStatement 是通过调用API,以及 占位符"?"的方式来设置参数 ,然后再使用setString()方法 发送到数据库去,也就是说SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1’也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了。
其实这么多字,就是想说使用预编译后最终会将你输入的内容当做类似于 文本 的感觉去处理,而不是像前面的会当做 代码块 去执行SQL指令,这样就能避免这种SQL注入了。
总结的来说,进行数据库传输时,使用预编译更加安全可靠。