从sql注入到web安全

一、事情起因

去年底的时候我看到几个国内开源框架又出来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和隔离设备必须定制化的通信协议,而不能使用标准的 mysql、oracle 等数据库通信协议,防止中间人风险(关基合规,民用可无视)

技术要点2:改写Mybatis源码成为定制化的orm组件,它读取 xml 和注解 中的 SQL 语句生成 AST 时将 SQL 关键词进行转化

SELECT、INSERT、UPDATE、DELETE、AND、OR、UNION  -- 等等关键词

例如将 SELECT 转为

{{#加密哈希#}}  -- 例如 {{#ERVEUZ#}}

2.1)在启动阶段,orm 会访问SQL隔离设备重新获取一套加密哈希表,将各个关键词对应的哈希进行缓存

2.2)orm 保持原有的使用习惯,但是只对 xml 和注解中的 SQL 进行转化,对外部输入并拼接的 SQL 数据是保持原样的

技术要点3:对SQL隔离设备的定制逻辑

3.1)只有使用 orm 才能访问隔离设备,防止中间人风险(关基合规,民用可无视)

3.3)隔离设备将接收到的 SQL 语句使用语义分析,把 SQL 关键词进行还原,发现未转化的 SQL 关键词则拦截执行并告警

3.4)对还原后的 SQL 语句进行整句的语义分析,应参照 Druid 的 wallfilter 对整句 SQL 进行安全校验

3.5)SQL 执行报错,生产模式下应输出脱敏后的SQL异常

3.6)提供需要SQL隔离设备管理员授权的特权审计接口,提供给需要动态输入 SQL 进行运营分析的场景

请看一个例子,orm中 XML 的 SQL:

select * from admin = ${id}

因为 select 和 from 是关键词需要转化,所以在 orm 中实际的 sql 为:

{{#ERVEUZ#}} * {{#QNULQU#}}  admin = ${id}

当外部输入 id 的参数内容为:

1 and 1 = 1

orm 传输到数据库中间件的内容就变为:

{{#ERVEUZ#}} * {{#QNULQU#}}  admin = 1 and 1 = 1 

数据库中间件的 AST 引擎分析发现应转化而未转化的关键词 and,中间件应拦截执行并告警

(我觉得我这个设计很好:-》,这算本文第二个产出)

 

四、Mybatis的Ognl以及SQL完整性

Mybatis 从SQL注入到OGNL注入(备用链接:Mybatis 从SQL注入到OGNL注入

Mybatis从SQL注入到OGNL表达式注入

Longlone's Blog

从上面三篇文章可以看出(在Param注解上大家存在争议),Mybatis的Ognl表达式引擎也是个爆点,这种方式可不管你${}拼接不拼接,直接就表达式注入了。

所以上述设计的数据库ORM如果以Mybatis为基础,就应去掉动态SQL这个特性,例如下图删掉Provider注解和SQL对象等等

去掉动态SQL其实就对应了信息安全三要素的完整性源码中的所有SQL都应保存在XML文件中以确保静态化,源码中的SQL语句除非${}拼接的特例否则应无法改变其语义。

(我觉得我这个构思很好:-》,这是对上一个设计的补强,安全理论还是很重要的)

 

 五、安全网关的规范

我们来看看一些WAF防护绕过的案例(来自于do9gy大哥的演讲):

下图是HTTP协议的chunke绕过WAF的例子

下图是HTTP协议的multipart解析差异绕过WAF的2个例子

等等诸如此类。

安全网关第1个技术要点:格式化,这个格式化分为大格式化和小格式化。

5.1)大格式化针对HTTP整个协议,对HTTP动词(GET、POST)、URL、各个HEADER头进行通用的SQL、XSS和路径穿越攻击都进行校验,如无风险则以HTTP分解符\r\n通过隔离设备发到内网数据库

分块传输技术绕过waf

搜集上述的类似恶意技巧都列入行为黑名单中,以保证HTTP格式可信

5.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注入
文件名一律校验后缀,网关可配置

QP编码上传恶意文件   

搜集上述的类似恶意技巧都列入行为黑名单中,以保证入参格式可信

5.3)最终内网的安全网关将数据库中格式化后的http数据重组为一个可信的HTTP请求,发送到指定应用。

 

安全网关第2个技术要点:安全网关应使用和内网应用同样的编程语言,以避免已知和未知的解析差异导致的格式化失效。

举例1  举例2     

可以参考Spring Security HttpFirewall 对特殊符号的处理   https://docs.spring.io/spring-security/reference/servlet/exploits/firewall.html

(我觉得我这个创意很好:-》,格式化是我看各种漏洞多年的感悟)

 

六、漏洞的免疫

因为隔离设备的缘故,所以内网的安全网关和应用都与互联网物理隔离,jndi注入、jar注入(利用URLClassLoader加载外部恶意jar)等手段是无法生效的。

但未知的反序列化还是可以起效,尤其是TemplatesImpl这个java内置类,其中java11算是个过渡版本不在考虑范围内。

所以我们要设计外网网关对未知漏洞防护的技术要点(java8):

6.1)进行充分的代码审计和java组件审计,防止产生常规漏洞。

6.2)使用 JAVA中的endorsed技术 对jndi注入相关的InitialContext类(参考JNDI注入高版本利用)和反序列化攻击相关的TemplatesImpl类(参考FastJson与原生反序列化)都进行重写,防止未知漏洞发生

6.3)采用防篡改技术对java目录、安全网关目录进行写入限制,防止恶意写入漏洞参考:Spring Boot Fat Jar 写文件漏洞到稳定 RCE 的探索

6.4)安装rasp探针,通过上下文识别技术以防护恶意的反序列化、反射、命令执行、表达式注入。

外网网关对未知漏洞防护的技术要点(java17或以上):

6.5)进行充分的代码审计和java组件审计,防止产生常规漏洞。

6.6)采用防篡改技术对java目录、安全网关目录进行写入限制,防止恶意写入漏洞参考:Spring Boot Fat Jar 写文件漏洞到稳定 RCE 的探索

6.7)安装rasp探针,通过上下文识别技术以防护恶意的反序列化、反射、命令执行、表达式注入,或者更推荐使用GraalVM进行AOT编译。

 

谢谢!

posted @ 2024-02-27 22:37  国产大熊猫~  阅读(170)  评论(0编辑  收藏  举报