原文地址:https://www.jianshu.com/p/ce6c51356b4e
0x00 背景
自己一个人学了这么久的web安全,感觉需要一些总结,加上今天下午电话面试总被问到的问题,自己总结了一下写出来和大家分享。(小白一个,也算自己记录一下,大佬勿喷)
0x01SQL注入实例
这里就以DVWA来做个示范,毕竟主要讲防御
low等级的注入无过滤直接提交id
LOW SQL
medium等级使用了mysqli_real_escape_string函数进行转义,被转义的包括\x00,\n,\r,\,’,”,\x1a(参考菜鸟教程)但是这种简单的转义很容易就被各种编码方式绕过。
MEDIUM SQL
high等级的代码采用了窗口跳转的方式,但是对于上交的数据始终没有处理就提交了,只是简单的在其后加了一个LIMIT 1,来限制取数据的行数,但是只要简单的使用#或者--+来注释掉就可以了。(感觉这个应该属于midium)
HIGH SQL
high等级的代码加入了token机制和PDO,基本防御了SQL注入。反正以我的水平和在网上查找的资料来看,好像没有成功注入的。
HIGH SQL
0x02
首先大前提是验证都处于服务器端,前端的验证形同虚设。
(1)使用PDO
PDO是PHP的一个扩展,为PHP访问数据库提供一个统一的接口,这就表明PDO可以连接不同类型的数据库系统,但是我们还是需要自己编写SQL语句。PDO随PHP5.1发行,在PHP5.0的PECL扩展中也可以使用,无法运行于之前的PHP版本,可以在phpinfo()中查看是否支持PDO。
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root');//设置编码以防止乱码
$sql ="SELECT id FROM user WHERE email=:email";
$stmt = $pdo->prepare($sql);
$email = filter_input(INPUT_GET,'email');
$stmt->bindValue(':email', $email);
上述代码中,:email是具名占位符,可以安全的绑定任意值。预处理语句会自动过滤$email的值,防止数据库收到SQL注入攻击。一个sql语句字符串中可以绑定多个具名占位符,然后在预处理语句中通过bindValue()方法绑定各个占位符的值。
(2)使用mysqli_query
MySQLi 扩展是在 PHP 5.0.0 版本中引进的,且只针对mysql数据库,但是其实大概原理和DBO相似,都是采用了prepare + bind 的写法。
$mysqli = new mysqli('localhost','username','password','database');
$query = $mysqli->prepare('
SELECT * FROM users
WHERE username = ?
AND email = ?
AND last_login > ?');
$query->bind_param('sss', 'test', $mail, time() - 3600);
$query->execute();
这个问号(?)绑定参数看上去很短,但是相比名称式参数缺少了灵活性,而且迫使开发者必须保证参数的顺序,有时候让人觉得很蛋疼。而且不幸的是MySQLi并不支持名称式参数。
(3)对输入进行转义处理
这一类主要是通过编程语言的预定义函数对输入转义,包括mysql_real_escape_string、addslashes()等,但是这一类函数存在一定的安全风险,不推荐使用。参见文章:PHP防SQL注入不要再用addslashes和mysql_real_escape_string了
(4)限制输入的内容
这其中包括对select、union等的过滤,但是这样一方面带来了对于用户使用的舒适性也有可能过滤不严格导致形同虚设。
(5)对输入编码
//这也算是一种处理各种注入的万能方法了,但是不足就是每次存取都需要编码或者解密,效率可能会降低。
SELECT password FROM users WHERE name = 'root' --普通方式
SELECT password FROM users WHERE name = 0x726f6f74 --防止注入
SELECT password FROM users WHERE name = UNHEX('726f6f74') --防止注入
(6)使用存储过程
存储过程是各种数据库的一种函数式编程方法,类似于预处理,只分配必要的数据库许可权限,有助于减轻SQL注入的影响——限制攻击者只能调用存储过程,从而限制了能够访问或修改的数据。由于SQL注入不仅能发生在应用层,还能发生在数据库层,因此如果攻击者将恶意语句写入到存储过程中,虽然访问和修改数据受到限制,但是如果在后续的动态SQL中使用了该输入,仍可能造成SQL注入。