一、事情起因
去年底的时候我看到几个国内开源框架又出来SQL注入,联想起HVV时候的各种OA、ERP的SQL注入。
我觉得SQL注入这个事情是该有人管管了。
二、Mybatis的一点回顾
https://github.com/mybatis/mybatis-3/issues/1941
如上,我在2020年开始就一直在和官方讨论${}的风险问题,官方认为过滤特殊符号并不是防御SQL注入的好策略。
但是大家去看一些CTF题目的答案,文章第一句很多都是“我们先试下哪些特殊符号被过滤了,哪些可以用”,所以我觉得基础的CTF都关注特殊符号,那么实战中特殊符号依然是web攻防的重点。
所以在上述github中我提了一个建议:
1)增加一个并列于#{}、${}的标签!{}
2)标签!{}之内只能输入大小写字母、数字和下划线(对应正则表达式为[a-zA-Z0-9_]),这样mybatis常见的like注入、in注入、order by注入就可以在不影响原有业务逻辑的情况下只替换一个特殊符号就修复漏洞
3)标签${}就只能在必须输入SQL的场景才能使用,对应的安全团队在代码审计时就可以降低工作负担。
(我觉得我这个建议很好:-》,这算本文第一个产出)
三、隔离设备的设计
已经发现若干行业都要求使用SQL隔离设备,保证数据库在内网并与互联网是物理隔离的。
这是安全合规的一部分,所以我在想应用的数据库orm组件和隔离设备之间是否可以增加安全设计以抵御SQL注入。
技术要点1:首先orm和隔离设备必须内置通讯加密机制,保证只有匹配的组件才能连接当前设备。(下文中假定我们以Mybatis为改造蓝本)
如上图,Mybatis其中有一个对${}拼接内容的安全过滤函数,可惜这个injectionFilter为空,而且用户无法定义injectionFilter的内容,实际上这个函数就是个空函数。
技术要点2:改写Mybatis源码,使这个checkInjection函数对${}的内容前后都增加SQL注释/*Dangerous*/,例如攻击者输入如下攻击SQL
' UNION SELECT NULL,VERSION()#
拼接完成后如下
/*Dangerous*/ ' UNION SELECT NULL,VERSION()# /*Dangerous*/
一旦将携带/*Dangerous*/注释的SQL发送到隔离设备,隔离设备就会先使用AST解析完整SQL并提取/*Dangerous*/注释中的拼接语句。
并对拼接语句执行安全策略:包括但不限于正则表达式、特殊符号限制、SQL白名单或者AI算法对拼接内容的威胁程度进行判断与拦截。
(AST语法解析SQL并进行威胁判断可参照 1.数据库连接池Druid 2.Druid配置)
技术要点3:如果真的出现用户需要输入SQL的业务场景(常见于数据分析、运营监控),一方面应限制到只能内网发起,另一方面可以对上面规则进行例外设计。
我设计的思路是:
1)数据库ORM和隔离设备内置一个心跳机制(不能利用SQL传输,防止内容被窃取),应用访问后隔离装置会返回一个uuid例如:583f298b-5229-4a02-a01e-9fb694476a2f
2)这个uuid默认缓存5分钟(缓存时间的时长,在隔离设备中可配置),一旦隔离设备接受到如下SQL内容:
/*Dangerous*//*583f298b-5229-4a02-a01e-9fb694476a2f*/ 用户输入的SQL /*583f298b-5229-4a02-a01e-9fb694476a2f*//*Dangerous*/
则隔离设备会无视/*Dangerous*/注释,因为uuid内容还在有效期内,所以应对用户输入的SQL不做任何安全拦截只做记录。
(我觉得我这个设计很好:-》,这算本文第二个产出)
四、Mybatis的Ognl以及SQL完整性
Mybatis 从SQL注入到OGNL注入(备用链接:Mybatis 从SQL注入到OGNL注入)
从上面三篇文章可以看出(在Param注解上大家存在争议),Mybatis的Ognl表达式引擎也是个爆点,这种方式可不管你${}拼接不拼接,直接就表达式注入了。
所以隔离设备的设计中的数据库ORM如果以Mybatis为基础,就应去掉动态SQL这个特性,例如下图删掉Provider注解和SQL对象等等
去掉动态SQL其实就对应了信息安全三要素的完整性,源码中的所有SQL都应保存在XML文件中以固定,SQL语句除非${}拼接的特例否则应无法改变其语义。
(这是对上一个设计的补强,理论还是很重要的)
四、安全网关的规范
我们来看看一些WAF防护绕过的案例(来自于do9gy大哥的演讲):
下图是HTTP协议的chunke绕过WAF的例子
下图是HTTP协议的multipart解析差异绕过WAF的2个例子
等等诸如此类。
安全网关第1个技术要点:格式化,这个格式化分为大格式化和小格式化。
1)大格式化针对HTTP整个协议,对HTTP动词(GET、POST)、URL、各个HEADER头进行通用的SQL、XSS和路径穿越攻击都进行校验,如无风险则以HTTP分解符\r\n通过隔离设备发到内网数据库
搜集上述的类似恶意技巧都列入行为黑名单中,以保证HTTP格式可信
2)小格式化针对URL中参数、BODY体中参数、multipart中参数和文件名,参照下列策略对入参执行白名单格式化校验,如无风险则通过隔离设备发到内网数据库
pI_为开头的key值(参考PositiveInteger),其value值必须为大于0的纯数字,例如pI_id为用户id号,网关校验一次格式后,后台就不用再校验数据格式
BD_为开头的key值,其value值为可以等于0的浮点,可类比bigdecimal
uBD_为开头的key值,其value值可以为大于等于0的浮点,可类比bigdecimal
S_为开头的key值,其value值只能为大小写字母、数字、中文和下划线
uS_为开头的key值(unsafe String),其value值则必须通过网关内置的SQL、XSS、表达式注入等检测,可参照WAF
而SQL语句则需要通过加密传输,否则一律会被识别为SQL注入
文件名一律校验后缀,网关可配置
搜集上述的类似恶意技巧都列入行为黑名单中,以保证入参格式可信
3)最终内网的安全网关将数据库中格式化后的http数据重组为一个可信的HTTP请求,发送到指定应用。
第二个要点是:安全网关应使用和内网应用同样的编程语言,以避免已知和未知的解析差异导致的格式化失效。
五、漏洞的免疫
因为隔离设备的缘故,所以内网的安全网关和应用都与互联网物理隔离,jndi注入则无法生效。但是未知的反序列化还是可以起效,尤其是TemplatesImpl这个java内置类。
所以我们要设计外网网关对未知漏洞的技术要点(java8):
1、使用 java的endorsed 对jndi注入相关的InitialContext类和反序列化攻击相关的TemplatesImpl类都进行重写,防止未知漏洞发生
2、采用防篡改技术对java目录、安全网关目录进行写入限制,防止恶意写入漏洞参考:Spring Boot Fat Jar 写文件漏洞到稳定 RCE 的探索
3、进行充分的代码审计和java组件审计,防止产生常规漏洞。
4、安装rasp探针,主要防护恶意的反序列化、反射、命令执行。
谢谢!
标签:web,网关,隔离,Dangerous,sql,SQL,Mybatis,注入 From: https://www.cnblogs.com/k4n5ha0/p/18038599