栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java中PreparedStatement和Statement详细讲解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java中PreparedStatement和Statement详细讲解

大家都知道PreparedStatement对象可以防止sql注入,而Statement不能防止sql注入,那么大家知道为什么PreparedStatement对象可以防止sql注入,接下来看我的案例大家就会明白了!

我用的是mysql数据库,以admin表为例子,如下图:

最后面有具体的java代码和sql代码案例

最终执行的sql语句打印出来是SELECt * FROM admin WHERe username = '韦小宝' AND password = '222' OR '8'='8'

从以上截图就能看出来,由此可见,prepareStatement对象防止sql注入的方式是把用户非法输入的单引号用反斜杠做了转义,从而达到了防止sql注入的目的

Statement对象就没那么好心了,它才不会把用户非法输入的单引号用反斜杠做转义呢!

PreparedStatement可以有效防止sql注入,所以生产环境上一定要使用PreparedStatement,而不能使用Statement

当然啦,你可以仔细研究下PreparedStatement对象是如何防止sql注入的,我自己把最终执行的sql语句打印出来了,看到打印出来的sql语句就明白了,原来是mysql数据库产商,在实现PreparedStatement接口的实现类中的setString(int parameterIndex, String x)函数中做了一些处理,把单引号做了转义(只要用户输入的字符串中有单引号,那mysql数据库产商的setString()这个函数,就会把单引号做转义)

大家有兴趣可以去网上,下载一份mysql数据库的驱动程序的源代码,看看mysql数据库产商的驱动程序的源代码,去源代码中找到setString(int parameterIndex, String x)函数,看看该函数中是怎么写的,我没有下载mysql数据库产商的驱动程序的源代码,而是把mysql数据库的驱动程序jar包解压了,找到了PreparedStatement.class文件,利用反编译工具,反编译了一下,如下:

这下大家应该知道PreparedStatement是如何防止sql注入的了吧

像222' OR '8'='8这样的sql注入还算温柔了,有些更可恶的用户,他们输入的非法的值是delete from tableName或truncate table tableName 这是十分危险的,更有甚者传入drop table tableName;有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句执行,所以生产环境上一定要使用PreparedStatement,而不能使用Statement

下面再举几个例子,看截图

最终打印SELECT * FROM admin WHERe username = '韦小宝' AND password = ''; DROp TABLE tableName;#'

最终打印SELECT * FROM admin WHERe username = '韦小宝' AND password = ''; delete from tableName;#'

最终打印SELECt * FROM admin WHERe username = '韦小宝' AND password = ''; truncate table tableName;#'

下面是java代码和sql语句,供大家参考,主要是为了测试PreparedStatement对象,所以java代码写的比较粗略,大家凑合着看吧!

package com.test;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 

public class TestConnMySql2 {
 
	public static void main(String[] args) {
		String connStr = "jdbc:mysql://localhost:3306/girls";
//		String sql = "select * from admin";
		String sql = "SELECt * FROM admin WHERe username = ? AND password = ?";
		try {
			Class.forName("com.mysql.jdbc.Driver");
			Connection connection = DriverManager.getConnection(connStr, "root", "root");
			System.out.println("数据库连接=" + connection);
			//Statement无法防止sql注入
//			Statement stmt = connection.createStatement();
	//PreparedStatement可以有效防止sql注入,所以生产环境上一定要使用PreparedStatement,而不能使用Statement
			PreparedStatement prepareStatement = connection.prepareStatement(sql);
			prepareStatement.setString(1, "韦小宝");
			//模拟用户输入正常的值
//			prepareStatement.setString(2, "222");
			//测试sql注入(模拟用户输入非法的值)
			prepareStatement.setString(2, "222' OR '8'='8");
			
			//测试sql注入(模拟用户输入非法的值)在mysql中#井号表示单行注释(这是mysql中的基础知识,我就不赘述了)
//			prepareStatement.setString(2, "'; DROp TABLE tableName;#");
			//测试sql注入(模拟用户输入非法的值)
//			prepareStatement.setString(2, "'; delete from tableName;#");
			//测试sql注入(模拟用户输入非法的值)
//			prepareStatement.setString(2, "'; truncate table tableName;#");
			
			ResultSet rs = prepareStatement.executeQuery();
			System.out.println("sql=" + prepareStatement.toString());
			int col = rs.getmetaData().getColumnCount();
			System.out.println("============================");
			while (rs.next()) {
				for (int i = 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 | SQLException e) {
			e.printStackTrace();
		}
 
	}
 
}
#用户输入正常合法的值
SELECt * FROM admin WHERe username = '韦小宝' AND `password` = '222';
#用户输入正常合法的值
SELECt * FROM admin WHERe username = '韦小宝' AND PASSWORD = '222';
 
#sql注入(用户输入非法的值)使用Statement对象,无法防止sql注入(会查询出表的所有数据)
SELECt * FROM admin WHERe username = '韦小宝' AND PASSWORD = '222' OR '8'='8'
#sql注入(用户输入非法的值)使用PreparedStatement对象,可以有效防止sql注入
SELECt * FROM admin WHERe username = '韦小宝' AND PASSWORD = '222' OR '8'='8'
 
#sql注入(用户输入非法的值)使用Statement对象,无法防止sql注入(DROp操作很危险)
SELECT * FROM admin WHERe username = '韦小宝' AND PASSWORD = ''; DROp TABLE tableName;#'
#sql注入(用户输入非法的值)使用PreparedStatement对象,可以有效防止sql注入
SELECT * FROM admin WHERe username = '韦小宝' AND PASSWORD = ''; DROp TABLE tableName;#'
 
#sql注入(用户输入非法的值)使用Statement对象,无法防止sql注入(TRUNCATE操作很危险)
SELECT * FROM admin WHERe username = '韦小宝' AND PASSWORD = ''; TRUNCATE TABLE tableName;#'
#sql注入(用户输入非法的值)使用PreparedStatement对象,可以有效防止sql注入
SELECt * FROM admin WHERe username = '韦小宝' AND PASSWORD = ''; truncate table tableName;#'
 
#sql注入(用户输入非法的值)使用Statement对象,无法防止sql注入(DELETe操作很危险)
SELECT * FROM admin WHERe username = '韦小宝' AND PASSWORD = ''; DELETe FROM tableName;#'
#sql注入(用户输入非法的值)使用PreparedStatement对象,可以有效防止sql注入
SELECt * FROM admin WHERe username = '韦小宝' AND PASSWORD = ''; delete from tableName;#'
 
#所以生产环境上一定要使用PreparedStatement,而不能使用Statement
 

 
#我是单行注释
 
-- 我也是单行注释(注意:-- 这种注释,后面必须要加一个空格,否则语法报错)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/136316.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号