SQL注入原理,利用,防护

sql injecton :

就是把sql命令插入到web表单递交或者输入域名或请求的查询字符串,最终达到欺骗服务器执行恶意的sql命令。

         具体来说:利用现有的应用程序(列:sqlmap),将恶意的sql命令注入到后台数据库引擎执行的能力,它可以通过web表单输入的sql语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行sql语句

 适用地: 

 假设我们在浏览器中输入url www.sample.com,由于它只是对页面的请求无需对数据库进行动态执行,所以它不存在sql injection,当我们输入www,salmap.com?testid=23时,我们在url中传递变量testID,并且提供值为23,由于它是对数据库进行动态的请求,(其中?testid = 23 表示数据库查询变量)所以我们可以在该地url中嵌入恶意sql语句

防御

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

2.过滤特殊符号:

对于无法确定固定格式的变量,一定要进行特殊符号过滤或者转义处理。

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

mysql的驱动提供了预编译语句的支持,不同的程序语句,都分别有使用预编译语句的方法。

实际上,绑定变量使用预编译语句是预防sql注入的最佳方式,使用预编译的sql语句寓意不会发生改变,在sql语句中,变量用?号?表示,黑客即使本事再大,也无法改变sql语句的结构。

但凡有sql注入的程序,都是因为程序要接受来自客户端用户的输入的变量或者传递的参数,并且这个变量或者参数是组成sql语句的一部分,对于用户输入的内容或传递的参数,我们应该要时刻保持警惕,这是安全领域里的【外部数据不可信任】的原则,纵观web安全领域的各种攻击方式,大多数都是因为开发者违反了这个原则而导致的,所以自然能想到的,就是从变量的检测,过滤,验证下手,确保变量是开发者所预想的。

什么是sql预编译?

通常我们的一条sql在db接收到最终执行完毕返回可以分为三个过程:

1.词义和语义解析

2.优化sql语句,制定执行计划

3.执行并返回结果

 

通常情况下,我们的一条sql语句可能会反复执行,或者每次执行的时候只有个别的值不同(比如query的where子句值不同,update的set子句值不同,insert的values值不同。

如果每次都需要经过上面的词法语义解析,语句优化,制定执行计划等,则效率就明显不行了】

所谓预编译语句就是将这类语句中的值用占位符替代,可以视为sql语句模板或者说参数化,一般称这类语句叫parameterized statements

预编译语句就是将这类语句中的值占位符代替,

注意mysql的老版本(4.1之前)是不支持服务端预编译的,但基于目前业界生产环境普遍情况,基本可以认为mysql支持服务端预编译。

建表

mysql> show create table t\G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE `t` (
  `a` int(11) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  UNIQUE KEY `ab` (`a`,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

编译

  我们接下来通过 PREPARE stmt_name FROM preparable_stm的语法来预编译一条sql语句

mysql> prepare ins from 'insert into t select ?,?';
Query OK, 0 rows affected (0.00 sec)
Statement prepared

  

执行

  我们通过EXECUTE stmt_name [USING @var_name [, @var_name] ...]的语法来执行预编译语句

mysql> set @a=999,@b='hello'; Query OK, 0 rows affected (0.00 sec) mysql> execute ins using @a,@b; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from t; +------+-------+ | a | b | +------+-------+ | 999 | hello | +------+-------+ 1 row in set (0.00 sec)

mysql的预编译语句作用域session级,但我们通过max_prepared_stmt_count变量来控制全局最大的存储的预编译语句

mysql> set @@global.max_prepared_stmt_count=1;
Query OK, 0 rows affected (0.00 sec)
 
mysql> prepare sel from 'select * from t';
ERROR 1461 (42000): Can't create more than max_prepared_stmt_count statements (current value: 1)

当我们想要释放一条预编译语句,则可以使用mysql会报如上所说的错误

为什么preparestatement可以防止sql注入

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

(1)为什么statement会被sql注入

因为statement之所以会被SQL注入是因为sql语句结构发生了变化,比如

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

在用户输入‘or true or '

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

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

 (2)为什么Preparement可以防止SQL注入。

  因为Preparement样式为

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

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

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

 

 

在mybatis编写映射语句时,尽量采用“#{xxx}" 这样的格式,若不结论l,要手工做好过滤工作,来防止sql注入攻击。

mybatis是如何做到防止sql注入

mybatis是一筐半自动化的持久层框架,其sql语句都要我们自己手动编写,这个时候当然要防止sql注入。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值