总篇120篇 2021年第15篇
前言
本文主要简述SQL注入漏洞原理、结合漏洞修复经验落地实践方式,最终描述整套的安全落地方案。通过本文可以了解常用测试SQL注入工具、不同修复方式的效果差异等。如对具体测试方法细节感兴趣,可查看注释或自行查询测试方法,受政策影响本文不再详细描述。安全是攻击与防御、矛与盾的结合体,只有彼此了解,才能“知己知彼,百战不殆”。
01
背景介绍
之家安全组结合现有情况,发现存在较多的SQL注入漏洞,这里简要介绍一下SQL注入漏洞:
根据OWASP TOP 10 2021最新数据,注入下滑至第三位,但该漏洞依旧普遍存在并有较严重的漏洞影响力,2013、2017版OWASP TOP10注入高居第一位。
OWASP(开放式Web应用程序安全项目)是一个开源的、非营利性的全球性安全组织,致力于改进Web应用程序的安全,这个组织最出名是,它总结了10种最严重的Web应用程序安全风险,警告全球所有的网站拥有者,应该警惕这些最常见、最危险的漏洞。这就是著名的OWASP Top 10。
SQL是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL。而SQL注入是将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以执行数据库命令。如Web应用程序的开发人员对用户所输入的数据或cookie等内容不进行过滤或验证(即存在注入点)就直接传输给数据库,就可能导致拼接的SQL被执行,获取对数据库的信息以及提权,发生SQL注入攻击。
具体举例:
<?php
$conn = mysqli_connect($servername, $username, $password, $dbname);
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$username = @$_POST['username'];
$password = @$_POST['password'];
$sql = "select * from users where username = '$username' and password='$password';";
$rs = mysqli_query($conn,$sql);
if($rs->fetch_row()){
echo "success";
}else{
echo "fail";
}
?>
上述代码将模拟一个web应用程序进行登录操作。若登录成功,则返回success,否则,返回fail。
通常正常用户进行登录的sql语句为:
select * from users where username = '$username' and password='$password'
其中,变量$username 与变量$password为用户可以控制的内容,正常情况下,用户所输入的内容在sql语义上都将作为字符,被赋值给前边的字段来当做整条select查询语句的筛选条件。
若用户输入的$username为admin'#,$password为123。那么拼接到sql语句中将得到如下结果:
select * from users where username = 'admin'#' and password='123'
这里的#是单行注释符,可以将后边的内容给注释掉。那么此条语句的语义将发生了变化,用户可以不需要判断密码,只需一个用户名,即可完成登录操作,这与开发者的初衷相悖。
同时SQL注入漏洞具有以下特征:
1、广泛性
任何一个基于SQL语言的数据库都可能被攻击,很多开发人员在编写Web应用程序时未对从输入参数、Web表单、cookie等接受到的值进行规范性验证和检测,通常会出现SQL注入漏洞。
2、隐蔽性
SQL注入语句一般都嵌入在普通的HTTP请求中,很难与正常语句区分开,所以当前许多防火墙都无法识别予以警告,而且SQL注入变种极多,攻击者可以调整攻击的参数,所以使用传统的方法防御SQL注入效果不理想。
3、危害大
攻击者通过SQL注入获取到服务器的库名、表名、字段名,从而获取到整个服务器中的数据,对网站用户的数据安全有极大的威胁。攻击者也可以通过获取到的数据,得到后台管理员的密码,然后对网页页面进行恶意篡改。这样不仅对数据库信息安全造成严重威胁,对整个数据库系统安全也影响重大。
4、操作方便
互联网上有很多SQL注入工具,简单易学,攻击过程简单,不需要专业知识也能自如运用。
对于实际的SQL注入类似场景举例,比较突破想象力:
交管系统摄像头录入车牌信息时,后面录入拼接的参数带入数据库可能就会执行语句造成意外的效果。
攻击者可能会利用所有输入参数的地方发动攻击,外部参数都可能存在漏洞利用的可能性,也就是一切来自外部的信息都要进行对应预处理及过滤,避免引入脏数据、可能的SQL命令执行等。
02
业务场景选型
发现业务系统存在该漏洞时,首选方案是进行参数化(prepared statement)查询方式修复代码,可以从根源彻底消除SQL问题,这里以mysql贴出代码示例:
UPDATE myTable SET c1 = ?c1, c2 = ?c2, c3 = ?c3 WHERE c4 = ?c
结合DBA的开发规范要求,使用参数化查询方式同时可提高SQL性能,可参考相关文章:【1】SQL书写规范
private const string SqlCommandKeywords = "and|exec|execute|insert|select|delete|update|count|chr|mid|master|" +
"char|declare|sitename|netuser|xp_cmdshell|or|create|drop|table|from|grant|use|group_concat|column_name|" +
"information_schema.columns|table_schema|union|where|select|delete|update|orderhaving|having|by|count|*|truncate|like";
private const string SqlSeparatKeywords = "'|;|--|\'|\"|/*|%|#";
实际发现问题落地时,经常会发现业务场景为老旧代码无人维护,或因历史遗留问题原因难以实现代码逻辑重构,这种时候的方案,建议是针对传递到后端的参数,可以上一个SQL过滤器,相当于一个软WAF的效果;
结合具体业务场景,有部分后台管理系统等业务上是有输入特殊符号的需求,这种可根据实际情况合理制定拦截脚本的规则。
SQL注入可以通过不同数据库特性进行特征性绕过,推荐开源的SQL工具SQLMAP【2】用于自查是否存在SQL注入漏洞。
这里总结下sqlmap的各种自动化bypass waf tamper,为攻击者的常见绕过防护攻击的方法,应针对这些手段重点进行防御:
apostrophemask.py 用UTF-8全角字符替换单引号字符
apostrophenullencode.py 用非法双字节unicode字符替换单引号字符
appendnullbyte.py 在payload末尾添加空字符编码
base64encode.py 对给定的payload全部字符使用Base64编码
between.py 分别用“NOT BETWEEN 0 AND #”替换大于号“>”,“BETWEEN # AND #”替换等于号“=”
bluecoat.py 在SQL语句之后用有效的随机空白符替换空格符,随后用“LIKE”替换等于号“=”
chardoubleencode.py 对给定的payload全部字符使用双重URL编码(不处理已经编码的字符)
charencode.py 对给定的payload全部字符使用URL编码(不处理已经编码的字符)
charunicodeencode.py 对给定的payload的非编码字符使用Unicode URL编码(不处理已经编码的字符)
concat2concatws.py 用“CONCAT_WS(MID(CHAR(0), 0, 0), A, B)”替换像“CONCAT(A, B)”的实例
equaltolike.py 用“LIKE”运算符替换全部等于号“=”
greatest.py 用“GREATEST”函数替换大于号“>”
halfversionedmorekeywords.py 在每个关键字之前添加MySQL注释
ifnull2ifisnull.py 用“IF(ISNULL(A), B, A)”替换像“IFNULL(A, B)”的实例
lowercase.py 用小写值替换每个关键字字符
modsecurityversioned.py 用注释包围完整的查询
modsecurityzeroversioned.py 用当中带有数字零的注释包围完整的查询
multiplespaces.py 在SQL关键字周围添加多个空格
nonrecursivereplacement.py 用representations替换预定义SQL关键字,适用于过滤器
overlongutf8.py 转换给定的payload当中的所有字符
percentage.py 在每个字符之前添加一个百分号
randomcase.py 随机转换每个关键字字符的大小写
randomcomments.py 向SQL关键字中插入随机注释
securesphere.py 添加经过特殊构造的字符串
sp_password.py 向payload末尾添加“sp_password” for automatic obfuscation from DBMS logs
space2comment.py 用“/**/”替换空格符
space2dash.py 用破折号注释符“–”其次是一个随机字符串和一个换行符替换空格符
space2hash.py 用磅注释符“#”其次是一个随机字符串和一个换行符替换空格符
space2morehash.py 用磅注释符“#”其次是一个随机字符串和一个换行符替换空格符
space2mssqlblank.py 用一组有效的备选字符集当中的随机空白符替换空格符
space2mssqlhash.py 用磅注释符“#”其次是一个换行符替换空格符
space2mysqlblank.py 用一组有效的备选字符集当中的随机空白符替换空格符
space2mysqldash.py 用破折号注释符“–”其次是一个换行符替换空格符
space2plus.py 用加号“+”替换空格符
space2randomblank.py 用一组有效的备选字符集当中的随机空白符替换空格符
unionalltounion.py 用“UNION SELECT”替换“UNION ALL SELECT”
unmagicquotes.py 用一个多字节组合%bf%27和末尾通用注释一起替换空格符
varnish.py 添加一个HTTP头“X-originating-IP”来绕过WAF
versionedkeywords.py 用MySQL注释包围每个非函数关键字
versionedmorekeywords.py 用MySQL注释包围每个关键字
xforwardedfor.py 添加一个伪造的HTTP头“X-Forwarded-For”来绕过WAF
如果对攻击者具体的绕过手段感兴趣,可以参考给出的链接查看绕过WAF的攻击渗透技巧,里面详细叙述了常见的绕过WAF方式,以此对过滤规则的编写和系统防御提供参考帮助。 【3】 【4】
商用产品方案:
可以部署WAF作为接入流量作为统一防护设备(硬件型、软件型、云或cdn部署WAF等),主要支持的功能:
1、HTTP、HTTPS协议的解析和过滤,如协议不同版本的识别和解析、协议参数长度限制等;
2、各类Web攻击防护,如:SQL注入、XSS跨站、CSRF、网页后门等;
3、各类自动化攻击防护,如:暴力破解、撞库、批量注册、自动发贴等;
4、阻止其它常见威胁,如:爬虫、0day攻击、代码分析、嗅探、数据篡改、越权访问、敏感信息泄漏、应用层DDoS、远程恶意包含、盗链、越权、扫描等;
5、其他管理与审计,如安全配置、日志分析、报表与统计功能等。
综合以上描述,代码修复方式漏洞修复最为彻底;加过滤器在代码较为简单,不过容易存在各种绕过行为等安全隐患;商业WAF规则及产品支持力度较好,且可以做通用的防护,但需要采购相关服务额外支持费用等。
03
总结
综合该漏洞的利用过程及危害,建议做以下防御策略,有部分正在结合安全组项目实际落地中:
1、分级管理
对具体角色进行分级管理,严格控制使用账号的权限,对于普通业务需求查询等,禁止给予数据库建立、删除、修改等相关权限,只有系统管理员才具有增、删、改、查的权限。例如上述实例中,外界输入信息在查询语句中加入了drop table。肯定是不能让其执行的,否则系统的数据库安全性就无法保障。
故而通过权限的设计限制。使得即使恶意攻击者在数据提交时嵌入了相关攻击代码。但因为设置了权限,从而使得代码不能执行。从而减少SQL注入对数据库的安全威胁。
2、参数传值
在写SQL语言时,禁止将变量直接写入到SQL语句,必须通过设置相应的参数来传递相关的变量。从而抑制SQL注入。数据输入不能直接嵌入到查询语句中。同时要过滤输入的内容,过滤掉不安全的输入数据。或者采用参数传值的方式传递输入变量。这样可以最大程度防范SQL注入攻击。
3、基础过滤与二次过滤
SQL注入攻击前,入侵者通过修改参数提交“and”等特殊字符,判断是否存在漏洞,然后通过select、update等各种字符编写SQL注入语句。因此防范SQL注入要对用户输入进行检查,确保数据输入的安全性,在具体检查输入或提交的变量时,对于单引号、双引号、冒号等字符进行转换或者过滤,从而有效防止SQL注入。当然危险字符有很多,在获取用户输入提交的参数时,首先要进行基础过滤,然后根据程序的功能及用户输入的可能性进行二次过滤,以确保系统的安全性。
目前安全组已立项在测试商业WAF进行业务线的流量过滤,采取嵌入式部署方式可对http及https流量进行过滤,正在验证WAF适配及可行性。
4、使用安全参数
SQL数据库为了有效抑制SQL注入攻击的影响。在进行SQLServer数据库设计时设置了专门的SQL安全参数。在程序编写时应尽量使用安全参数来杜绝注入式攻击。从而确保系统的安全性。
SQLServer数据库提供了Parameters集合,它在数据库中的功能是对数据进行类型检查和长度验证,在程序设计时加入了Parameters集合后,系统会自动过滤掉用户输入中的执行代码,识别其为字符值。如果用户输入中含有恶意的代码,数据库在进行检查时也能够将其过滤掉。同时Parameters集合还能进行强制执行检查。一旦检查值超出范围。系统就会出现异常报错,同时将信息发送系统管理员,方便管理员做出相应的防范措施。
5、漏洞扫描
为了更有效地防范SQL注入攻击,作为系统管理除了设置有效的防范措施,更应该及时发现系统存在SQL攻击安全漏洞。可以通过采购专门的SQL漏洞扫描工具,通过专业的扫描工具,可及时的扫描到系统存在的相应漏洞。
漏洞扫描工具只能扫描到SQL注入漏洞,不能防范SQL注入攻击。但可以通过扫描到的安全漏洞,根据不同的情况采取相应的防范措施封堵相应的漏洞,从而把SQL注入攻击的门给关上,从而确保系统的安全。
目前安全组已有商业扫描器,可使用被动代理模式进行全参数的扫描,发现漏洞可及时进行处置。同时安全组目前在调研将商业扫描器接入交付流水线的可行性,尽可能将漏洞消灭在部署上线前以避免安全事故的发生。
6、多层验证
7、数据库信息加密
传统的加解密的方法大致可以分为三种:
(1)对称加密:即加密方和解密方都使用相同的加密算法和密钥,这种方案的密钥的保存非常关键,因为算法是公开的,而密钥是保密的,一旦密匙泄露,黑客仍然可以轻易解密。常见的对称加密算法有:AES、DES等。
(2)非对称加密:即使用不同的密钥来进行加解密,密钥被分为公钥和私钥,用私钥加密的数据必须使用公钥来解密,同样用公钥加密的数据必须用对应的私钥来解密,常见的非对称加密算法有:RSA等。
(3)不可逆加密:利用哈希算法使数据加密之后无法解密回原数据,这样的哈希算法常用的有:md5、SHA-1等。
结合今年国家颁布并实行的《数据安全法》、《个人信息保护法》及17年颁布的《网络安全法》,安全组正在实施数据库敏感数据检测的项目,统计敏感数据信息,进行统一的治理。落地完成数据库敏感信息加密后,通过密文存储的数据即使通过SQL注入漏洞将数据拖出,也不能查看进行直接的利用,降低了数据泄露的风险。
引用
【1】SQL书写规范: https://blog.csdn.net/blockhouse_fly/article/details/23660223
【2】SQLMAP:https://github.com/sqlmapproject/sqlmap
【3】bypass waf 相关:https://paper.seebug.org/218/
【4】MYSQL注入技巧:https://xz.aliyun.com/t/7169
作者简介