java中PreparedStatement和Statement详细讲解
大家都知道PreparedStatement对象可以防止sql注入,而Statement不能防止sql注入,那么大家知道为什么PreparedStatement对象可以防止sql注入,接下来看我的案例大家就会明白了!
我用的是mysql数据库,以admin表为例子,如下图:
最后面有具体的java代码和sql代码案例
最终执行的sql语句打印出来是SELECT*FROMadminWHEREusername='韦小宝'ANDpassword='222\'OR\'8\'=\'8'
从以上截图就能看出来,由此可见,prepareStatement对象防止sql注入的方式是把用户非法输入的单引号用\反斜杠做了转义,从而达到了防止sql注入的目的
Statement对象就没那么好心了,它才不会把用户非法输入的单引号用\反斜杠做转义呢!
PreparedStatement可以有效防止sql注入,所以生产环境上一定要使用PreparedStatement,而不能使用Statement
当然啦,你可以仔细研究下PreparedStatement对象是如何防止sql注入的,我自己把最终执行的sql语句打印出来了,看到打印出来的sql语句就明白了,原来是mysql数据库产商,在实现PreparedStatement接口的实现类中的setString(intparameterIndex,Stringx)函数中做了一些处理,把单引号做了转义(只要用户输入的字符串中有单引号,那mysql数据库产商的setString()这个函数,就会把单引号做转义)
大家有兴趣可以去网上,下载一份mysql数据库的驱动程序的源代码,看看mysql数据库产商的驱动程序的源代码,去源代码中找到setString(intparameterIndex,Stringx)函数,看看该函数中是怎么写的,我没有下载mysql数据库产商的驱动程序的源代码,而是把mysql数据库的驱动程序jar包解压了,找到了PreparedStatement.class文件,利用反编译工具,反编译了一下,如下:
这下大家应该知道PreparedStatement是如何防止sql注入的了吧
像222'OR'8'='8这样的sql注入还算温柔了,有些更可恶的用户,他们输入的非法的值是deletefromtableName或truncatetabletableName这是十分危险的,更有甚者传入droptabletableName;有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句执行,所以生产环境上一定要使用PreparedStatement,而不能使用Statement
下面再举几个例子,看截图
最终打印SELECT*FROMadminWHEREusername='韦小宝'ANDpassword='\';DROPTABLEtableName;#'
最终打印SELECT*FROMadminWHEREusername='韦小宝'ANDpassword='\';deletefromtableName;#'
最终打印SELECT*FROMadminWHEREusername='韦小宝'ANDpassword='\';truncatetabletableName;#'
下面是java代码和sql语句,供大家参考,主要是为了测试PreparedStatement对象,所以java代码写的比较粗略,大家凑合着看吧!
packagecom.test;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.PreparedStatement;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.sql.Statement;
/*
*研究PreparedStatement是如何防止sql注入的,我分析了一下,原来是mysql数据库产商,在实
*现PreparedStatement接口的实现类中的setString(intparameterIndex,Stringx)函
*数中做了一些处理,把单引号做了转义(只要用户输入的字符串中有单引号,那mysql数据库产商的setString()这个函
*数,就会把单引号做转义)
*/
publicclassTestConnMySql2{
publicstaticvoidmain(String[]args){
StringconnStr="jdbc:mysql://localhost:3306/girls";
// Stringsql="select*fromadmin";
Stringsql="SELECT*FROMadminWHEREusername=?ANDpassword=?";
try{
Class.forName("com.mysql.jdbc.Driver");
Connectionconnection=DriverManager.getConnection(connStr,"root","root");
System.out.println("数据库连接="+connection);
//Statement无法防止sql注入
// Statementstmt=connection.createStatement();
//PreparedStatement可以有效防止sql注入,所以生产环境上一定要使用PreparedStatement,而不能使用Statement
PreparedStatementprepareStatement=connection.prepareStatement(sql);
prepareStatement.setString(1,"韦小宝");
//模拟用户输入正常的值
// prepareStatement.setString(2,"222");
//测试sql注入(模拟用户输入非法的值)
prepareStatement.setString(2,"222'OR'8'='8");
/*
*上面那种的sql注入还算温柔了,有些更可恶的用户,他们输入的非
*法的值是deletefromtableName或truncatetabletableName这是十分危险的,
*更有甚者传入droptabletableName;有些数据库是不会让你成功的,但也有很多数
*据库就可以使这些语句执行,所以生产环境上一定要使用PreparedStatement,而不能使用Statement
*/
//测试sql注入(模拟用户输入非法的值)在mysql中#井号表示单行注释(这是mysql中的基础知识,我就不赘述了)
// prepareStatement.setString(2,"';DROPTABLEtableName;#");
//测试sql注入(模拟用户输入非法的值)
// prepareStatement.setString(2,"';deletefromtableName;#");
//测试sql注入(模拟用户输入非法的值)
// prepareStatement.setString(2,"';truncatetabletableName;#");
ResultSetrs=prepareStatement.executeQuery();
System.out.println("sql="+prepareStatement.toString());
intcol=rs.getMetaData().getColumnCount();
System.out.println("============================");
while(rs.next()){
for(inti=1;i<=col;i++){
System.out.print(rs.getString(i)+"\t");
if((i==2)&&(rs.getString(i).length()<8)){
System.out.print("\t");
}
}
System.out.println("");
}
System.out.println("============================");
rs.close();
prepareStatement.close();
connection.close();
}catch(ClassNotFoundException|SQLExceptione){
e.printStackTrace();
}
}
}
#用户输入正常合法的值 SELECT*FROMadminWHEREusername='韦小宝'AND`password`='222'; #用户输入正常合法的值 SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='222'; #sql注入(用户输入非法的值)使用Statement对象,无法防止sql注入(会查询出表的所有数据) SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='222'OR'8'='8' #sql注入(用户输入非法的值)使用PreparedStatement对象,可以有效防止sql注入 SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='222\'OR\'8\'=\'8' #sql注入(用户输入非法的值)使用Statement对象,无法防止sql注入(DROP操作很危险) SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='';DROPTABLEtableName;#' #sql注入(用户输入非法的值)使用PreparedStatement对象,可以有效防止sql注入 SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='\';DROPTABLEtableName;#' #sql注入(用户输入非法的值)使用Statement对象,无法防止sql注入(TRUNCATE操作很危险) SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='';TRUNCATETABLEtableName;#' #sql注入(用户输入非法的值)使用PreparedStatement对象,可以有效防止sql注入 SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='\';truncatetabletableName;#' #sql注入(用户输入非法的值)使用Statement对象,无法防止sql注入(DELETE操作很危险) SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='';DELETEFROMtableName;#' #sql注入(用户输入非法的值)使用PreparedStatement对象,可以有效防止sql注入 SELECT*FROMadminWHEREusername='韦小宝'ANDPASSWORD='\';deletefromtableName;#' #所以生产环境上一定要使用PreparedStatement,而不能使用Statement /* 顺便复习一下mysql中的3种注释,我是多行注释 */ #我是单行注释 --我也是单行注释(注意:--这种注释,后面必须要加一个空格,否则语法报错)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。