关于对SQL注入问题与SQL执行过程的理解与简述(基于JDBC)

发布时间 2024-01-09 18:37:48作者: 进步·于辰

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://www.cnblogs.com/cnb-yuchen/p/17955065
出自【进步*于辰的博客

参考笔记一,P52.2/3。

1、SQL注入

大家看这条SQL语句:

String sql = "select * from users where username = '"
			 + name + + "' and password = '" + pass + "'";

这是一条由字符串拼接而成的登录SQL语句。当用户名、密码都匹配时,才能查询出用户信息,进而登录成功。

用户名和密码由表单输入,假设一种情况:

name = "yc"
pass = "123' or 1 = 1"

那拼接出的SQL语句就是:

String sql = "select * from users where username = 'yc' 
			and password = '123' or 1 = 1";

如此,用户名和密码已无效,皆可登录成功。

那到底什么是SQL注入?
“SQL注入”是指恶意输入表单数据,利用程序存在先生成SQL语句,后编译的漏洞,使数据库编译器误将表单数据中的字符串识别为数据库关键字,而导致SQL语句“异常”执行,进而表单失效的问题。

上述例子,pass 中带有"or",本是字符串,但数据库编译器将其识别为or关键字。

2、SQL语句执行过程

需要注意一点,以下整个过程都是在数据库中执行。

  • 第一步:sql传输。表单数据提交,sql语句拼接完成,sql语句从程序传输至数据库;
  • 第二步:验证。验证sql语句是否正确;
  • 第三步:编译。由数据库编译器对sql语句进行编译(具体编译情况,比如:编译后文件类型是什么?存放在哪里?本人暂不清楚,大家用java编译理解就行);
  • 第四步:执行判断。判断内存中是否存在具有相同sql语句的临时表。若存在,获取临时表返回给程序;
  • 第五步:执行。sql语句首次执行,数据库会将sql语句和相应结果集生成并存入临时表。临时表存储于内存,而数据库存储于磁盘,故前者执行速度快于后者。

“执行判断”中一个需要注意的问题:
访问数据库时,只要重新执行sql语句即可实现刷新(重新访问),可实际上无法实现。因为sql语句执行后,会生成临时表,如果连接未关闭,临时表就仍然存在。在重新执行相同sql语句时,不会访问数据库,即无法实现刷新。

3、如何防止“SQL注入”?

(基于JDBC)当执行executexx()时,sql语句会经历以上五个步骤,由于先拼接sql语句再进行编译,故数据库会误将“or”“and”等字符串识别为关键字,从而导致SQL注入问题。

解决方法:将执行对象 Statement 换成 PreparedStatement。
原理:

  1. PreparedStatement 类属于预编译。在实例化时,即conn.preparedStatement(sql),载入了sql语句,故在程序中完成了 验证编译
  2. Statement 类是将变量拼接进sql语句;而PreparedStatemet 类是为变量提供占位符“?”供变量赋值,这些变量称为$\color{green}{预变量}$。
    当为“预类型”为 String 的占位符赋值时,无论变量值包含什么,都会将其视为字符串,也解决SQL注入问题。
    -注:当使用 PreparedStatement 类时,由于变量位置由占位符代替,摆脱了变量作用域限制,故可实现$sql语句的共享$。

本文完结。