SQL注入问题&&PreparedStatement

SQL注入问题

 我们来看账号登录程序(点击)的代码,我们表中的数据为:

                       

我们运行输入如下数据:

                                     

竟然运行成功了。

我们思考,上面输入的数据用户名一看就是瞎写的,但是密码看起来貌似和很有章法,or 和单引号都容易让我们想到sql语句中的判断语句
所以我们观察代码,为什么会出现随便输入都能成功的现象呢。

这是因为我们在之前的代码中进行有这样的代码:

我们打开注释,按上面的输出输出这句话:

我们观察最后传入数据库的语句,字符串在之前会进行拼接,然后就会返回一个一定对的答案。然后数据再进行判断,就会返回一条信息,我们之前的思路是如果查找成功那么就会返回一条数据,只要判断next()方法的返回值是否为false就行了。但是现在,我们发现,这样做是有很大漏洞的。

而这个漏洞,就叫做SQL注入问题。 据说,在十几年前,所有的需要账号密码的网站都可以这样破译。


我们需要传入SQL语句,最好的方法就是String语句,而且必须和外来的输入无法拼接一起传入数据库,貌似无懈可击,那么这个漏洞怎么破呢。

JAVA研发人员退出了PreparedStatement类:预编译类


PreparedStatement

 PreparedSatement的执行原理

我们写的SQL语句让数据库执行,数据库不是直接执行SQL语句字符串。和Java一样,数据库需要执行编译后的SQL语句(类似Java编译后的字节码文件)

Satement对象每执行一条SQL语句都会先将这条SQL语句发送给数据库编译,数据库再执行。 

Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO users VALUES (1, '张三', '123456');");
stmt.executeUpdate("INSERT INTO users VALUES (2, '李四', '666666');");

上面2条SQL语句我们可以看到大部分内容是相同的,只是数据略有不一样。数据库每次执行都编译一次。如果有1万条类似的SQL语句,数据库需要编译1万次,执行1万次,显然效率就低了。

prepareStatement()会先将SQL语句发送给数据库预编译。PreparedStatement会引用这预编译后的结果。可以多次传入不同的参数给PreparedStatement对象并执行。相当于调用方法 多次传入不同的参数。

//这里的问号是占位符。表示占住这个位置,等会儿再填数据
String sql = "INSERT INTO users VALUES (?, ?, ?);";
// 会先将SQL语句发送给数据库预编译。PreparedStatement会引用着预编译后的结果。
PreparedStatement pstmt = conn.prepareStatement(sql);

 

// 设置参数,这里的1,2,3都是表示上面我们传入的sql语句中问号的顺序,1表示第一个问号,2表示第二个问号
// 默认是从1开始的
pstmt.setInt(1, 1);
pstmt.setString(2, "张三");
pstmt.setString(3, "123456");
pstmt.executeUpdate();

// 再次设置参数
pstmt.setString(1, 2);
pstmt.setInt(2, "李四");
pstmt.setString(3, "66666");
pstmt.executeUpdate();

上面预编译好一条SQL,2次传入了不同的参数并执行。如果有1万条类似的插入数据的语句。数据库只需要预编译一次,传入1万次不同的参数并执行。减少了SQL语句的编译次数,提高了执行效率。

PreparedSatement的好处

  • prepareStatement()会先将SQL语句发送给数据库预编译。PreparedStatement会引用着预编译后的结果。可以多次传入不同的参数给PreparedStatement对象并执行。减少SQL编译次数,提高效率。
  • 安全性更高,没有SQL注入的隐患。
  • 提高了程序的可读性

 PreparedSatement的基本使用

(1)API介绍

1)获取PreparedSatement的API介绍

在java.sql.Connection有获取PreparedSatement对象的方法

PreparedStatement prepareStatement(String sql)
会先将SQL语句发送给数据库预编译。PreparedStatement对象会引用着预编译后的结果。

2)8.2.1.2 PreparedSatement的API介绍

在java.sql.PreparedStatement中有设置SQL语句参数,和执行参数化的SQL语句的方法

void setDouble(int parameterIndex, double x)
将指定参数设置为给定 Java double 值。

void setFloat(int parameterIndex, float x)
将指定参数设置为给定 Java float 值。

void setInt(int parameterIndex, int x)
将指定参数设置为给定 Java int 值。

void setLong(int parameterIndex, long x)
将指定参数设置为给定 Java long 值。

void setObject(int parameterIndex, Object x)
使用给定对象设置指定参数的值。  

void setString(int parameterIndex, String x)
将指定参数设置为给定 Java String 值。

ResultSet executeQuery()
在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的ResultSet对象。

int executeUpdate()
在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言(Data Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。

(2)PreparedSatement使用步骤

编写SQL语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND password=?;";

获得PreparedStatement对象

设置实际参数

执行参数化SQL语句

关闭资源


我们再对登录程序进行优化。代码

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值