SQL注入详解

2023-11-13

一、什么是SQL注入

SQL注入是一种将SQL代码添加到输入参数中,传递到SQL服务器解析并执行的一种攻击方式

select * from table where name="+appName+"

攻击者利用appName参数值的输入,来生成恶意的SQL语句,比如将or ‘1’=‘1’这样的语句传入,即可在数据库中恶意执行。

SQL注入的产生原因:(SQL语句存在拼接)

  • web开发人员无法保证所有的输入数据都已经过滤
  • 攻击者利用发送给SQL服务器的输入数据构造可执行的代码
  • 数据库未做相应的安全配置,比如对web应用的数据库,使用简单操作权限的账号登陆,回收一些类似drop的操作权限

 

二、SQL注入攻击的总体思路

  • 寻找到SQL注入的位置
  • 判断服务器类型和后台数据库类型
  • 针对不同的服务器和数据库特点进行SQL注入攻击

 

三、SQL注入攻击实例

//原SQL语句
select * from user_table where username='"+userName+"' and password='"+password+"';


//SQL注入攻击
select * from user_table where username=' '' or 1=1-- and password='';


//分析:
//'' or 1=1 --
//第一部分'' or 1=1 表示用户名等于''或者1=1,那么这个条件一定会成功
//第二部分--表示注释,它将后面的语句注释,让它们不起作用,这样语句永远都能正确执行,用户可以轻易骗过系统,获取合法身份


//恶意SQL注入攻击
select * from user_table where username='' ;DROP DATABASE (DB NAME) --' and password='';
//这样的恶意SQL注入攻击会直接删除数据库

 

四、预防SQL注入

注意:但凡是SQL注入漏洞程序,都是因为程序要接收来自客户端用户输入的变量或者URL传递的参数,并且这个变量或参数是组成SQL语句的一部分。

(1)检查变量数据类型和格式

如果SQL语句是类似where id={}这种格式,数据库中所有的id都是数字,那么就应该在SQL被执行前,确保变量id是int类型;如果是接收邮箱,那就应该检查并严格确保变量一定是邮箱格式,其他的类型,比如日期,时间也是一个道理。总结起来,即是,只要是固定格式的变量,在SQL语句执行前,应该严格按照固定格式去检查,确保变量是我们预想的格式,这样很大程度上可以避免SQL注入攻击。

例如,我们前面接收userName参数例子中,我们的产品设计应该是在用户注册的一开始,就有一个用户名的规则,比如5-20个字符,只能由大小写字母,数字以及一些安全的符号组成,不包含特殊字符。此时,我们应该有一个check_userName的函数来进行统一的检查。不过,仍然有很多例外的情况并不能应用到这一个准则,比如文章发布系统,评论系统等必须要允许用户提交任意字符串的场景,这样就需要采用过滤等其他方案了。

(2)过滤特殊符号

对于无法确定固定格式的变量,一定要进行特殊符号过滤或转义处理(比如MySQL数据库中,--表示的注释字符)

(3)绑定变量,使用预编译语句

绑定变量使用预编译语句是预防SQL注入的最佳方式,使用预编译的SQL语句,其语义不会发生改变,在SQL语句中,变量用占位符(?) 表示,攻击者即使本事再大,也无法改变SQL语句的结构。

 

五、预编译(Statement和PreparedStatement)

通常我们一条SQL语句(Statement)在数据库接收到最终执行完毕可以分为三个阶段:语法和语句解析,优化SQL语句并制定执行计划,执行结果并返回。

很多情况下,我们的一条SQL语句可能会被反复执行,或者每次执行的时候只有个别的值不同(比如Query的where子句值不同,Update的set子句值不同,Insert的values值不同)。如果每次都需要经过上面的语法语义解析,语句优化,执行执行计划等,则效率就明显不足。

所谓预编译语句就是将这类语句中的值用占位符替代,可以视为SQL语句模板化或者参数化,一般称这种语句叫PreparedStatement。编译语句的优势在于:一次编译,多次运行,省去了解析优化等过程,此外预编译语句可以防止SQL注入

 

六、PreparedStatement为什么可以防止SQL注入?

PreparedStatement的原理是采用了预编译方法,先将SQL语句中可被客户端控制的参数集进行编译,生成对应的临时变量集,再使用相应的设置方法,为临时变量集里面的元素进行赋值,如赋值函数(setString(),setInt()等),会对传入的参数进行强制类型检查和安全检查,所以能避免SQL注入的产生。

具体分析如下:

(1)Statement会被SQL注入

Statement之所以会被SQL注入是因为SQL语句结构发生了变化。比如:

"select*from tablename where username='"+uesrname+  
"'and password='"+password+"'"

在用户输入‘or true or’之后SQL语句结构改变

select*from tablename where username=''or true or'' and password=''

这样本来判断用户名和密码都匹配时才会技术,但是经过改变后,变成了或的逻辑关系,不管用户名和密码是否匹配,该式的返回值永远为true。

(2)PreparedStatement可以防止SQL注入

PreparedStatement的语句格式如下:

select*from tablename where username=? and password=?

该SQL语句会在得到用户的输入之前先用数据库进行预编译,这样的话不管用户输入什么用户名和密码,判断始终是并的逻辑关系,可以防止SQL注入。

简单总结,参数化可以防止SQL注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑,至于跑的时候是带一个普通背包还是一个怪物,不会影响行进路线,无非跑的快和慢的区别。

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQL注入详解 的相关文章

随机推荐