前几年在风险防控上做了一个静态分析的工具和一个动态分析的工具,本文是对静态分析技术和变更影响技术做一个阶段性的总结。
1. 背景
1.1 遇到的问题
随着金融业务规模和影响力越来越大,很多金融产品达到亿级用户千亿资金规模、已经不能承受大的资损故障和风险事件,所以安全生产是亿级用户规模产品最核心的事,目标是打造核电站安全级别的金融平台,实现【0风险事件0资损故障】。而现在在金融领域安全生产上面临的挑战是,因为系统链路极长和业务复杂导致【场景分析容易遗漏】从而引发线上问题。
场景分析遗漏。金融产品50%以上的线上问题是因为测分和系分场景遗漏导致,这个和风险字段多也有一定的关系,随着金融产品不断迭代,离线和在线全部加在一起可能达上千个风险字段,从理论上看,我觉得所有操作风险字段的代码块都是风险点,那么风险点的个数应该在几千这个级别,所以场景分析和风险防护的压力较大。
1.2 解决思路
目前为了保证场景分析无遗漏,主要还是强依赖于专家经验,对整个业务链路越熟悉的开发评估遗漏的可能性越小。评估花的时间越长越仔细遗漏的可能性越小,但是有些场景如果开发不知道,那么评估再长的时间也是会遗漏。所以靠人的专家经验解决是不可能完全避免遗漏的,因为人总会百密一疏。
因此需要从人力解决到通过算力解决,将专家经验转换成系统能力,建设自动化的技术风险评估能力,我们希望通过静态分析技术来建设变更影响洞察能力。以变更代码作为输入,通过程序静态分析等技术建设产品能力,推导出变更影响的业务场景、用例和核对等
我们要完成的事情是通过变更的代码推导出变更影响的【JAVA字段】和【DB字段】,再通过DB字段推导出变更影响的【用例】和【核对】等。
1.3 确定目标
变更洞察的目标是减少因场景评估遗漏引起的线上问题个数,目标为降低50%以上。
2. 解决方案
2.1 领域建模
变更影响从模型关系上的推导逻辑是
通过变更代码行匹配切片代码行
通过切片代码行找到对应程序切片
通过程序切片找到兴趣点里的模型字段
通过模型字段分析出DB字段
通过DB字段分析出核对。
通过DB字段找相关的用例。
2.2 实现方案
变更洞察由以下四个步骤组成:
源码变更通知:整个变更洞察由代码变更事件驱动,驱动完之后对系统进行打包。
程序切片分析:从字节码中抽取某个字段对应的程序切片。
影响字段分析:通过变更分析找到变更影响的DB字段。
变更影响分析:基于DB字段分析影响的用例和核对。
2.3 什么是变量血缘
变量血缘是指在一个系统中变量与变量之间的关系,变量血缘需要通过分析方法调用链和方法内变量关系获取到。
2.4 源码变更通知
因为程序切片分析是基于字节码进行分析,所以在分析之前需要将源码进行编译和打包。
变更前:变更前对应的是某系统的release版本,当收到Tag Push事件时鲁班会使用antcode对其进行编译打包。
变更后:变更后对应的是某系统当前迭代分支,当收到迭代的MR事件时,鲁班会使用antcode对其进行编译打包。
2.5 程序切片抽取
2.5.1 什么是程序切片
程序切片分析是一种静态分析技术,简单理解程序切片是指和某行代码相关的代码片段,这些代码片段被称为程序切片,这个解释可能还是比较抽象,举个例子来说明下,以下是一个向后的程序切片的例子,红色的部分表示语句printf("%d\n",i);的程序切片,printf("%d\n",i);被称为程序切片的兴趣点。
执行切片分析之后,可以发现和i这个变量无关的代码都没了,剩下的代码都和i变量有关系,以此类推程序切片里的所有的变量都和i有关系,且这种关系会有两种一种是基于数据的,一种是基于条件的,i=i+1和兴趣点的关系是基于数据的,while(i<11)和兴趣点的关系是基于条件的。
以下是向前切片的例子
2.5.2 获取兴趣点
程序切片抽取的入参是兴趣点和程序的字节码,输出的是这个兴趣点的程序切片,我们通过红蓝攻防拿到所有需要防控的DB字段,通过程序的SQLMAP解析出对应的JAVA字段,将这些JAVA字段所在代码行作为程序切片的兴趣点。
2.5.3 JAVA字段到程序切片
程序静态分析在理论上就达不到100%完全正确的状态(complete),要么出现误报要么出现漏报,而我们要解决的问题就是避免遗漏,所以我们选择的方向是减少漏报,因此使用双静态分析引擎来实现程序切片然后取两个切片的并集,这样能尽量避免漏报。双引擎一个是公司内部静态分析引擎,一个是使用WALA开源框架,并且为了提升精度我们在wala开源框架的基础上优化了指针分析算法,并提交patch给wala团队。
2.6 影响字段分析
影响字段分析的步骤是,通过diff代码和程序切片进行分析是否影响某个程序切片,再通过程序切片拿到对应的JAVA字段,再通过分析sqlmap拿到JAVA字段对应的DB字段。
2.6.1 变更影响的JAVA字段
变更代码有三种情况,新增代码、删除代码和修改代码,修改代码可以看做是新增和删除代码的组合。变更前的代码知道删除了哪些代码,变更后的代码知道新增哪些代码,所以要分析变更影响,必须拿到变更前的程序切片和变更后的程序切片,将迭代前的程序切片和删除的代码做交集,将迭代后的代码和新增的代码做交集,如果有交集则证明变更影响了这个程序切片,拿到切片之后就知道变更影响了哪个JAVA字段。
2.6.1 变更影响的DB字段
通过解析sqlmap文件中的resultMap标签得到JAVA字段和DB字段的关系。
3. 代码静态分析优化
3.1 变量血缘分析遇到的问题
要分析出系统内部的变量血缘关系,要解决分析精度、分析速度和分析规模三类问题。我们整理了下14个精度问题,1个速度问题和1个分析规模问题。
3.2 核心解法分析
我们全面分析了下,一共有17个核心问题需要解决,解决方案有的是通过实现论文算法,如回调等,有的是通过引入动态分析来解决,如跨系统等。
序号 | 问题分类 | 问题子类 | 问题点 | 解法 |
1 | 系统级精度问题 | 系统调用链断开 | 消息通讯 | 依赖动态链路刻画 |
2 | RPC通讯 | |||
3 | 系统调用关系错误 | SPI调用 | ||
4 | 方法级精度 | 调用链断开 | IOC容器创建实例 | 实现论文算法《dispatch改进》提升效果-40% |
5 | 回调调用 | |||
6 | 反射调用 | 依赖动态链路刻画 | ||
7 | 异步调用 | |||
8 | 切面拦截 | |||
9 | 动态代理 | |||
10 | 配置类 | |||
11 | 调用链错误 | 单接口多实现 | 实现论文《对象敏感性优化 》和《混合敏感性分析》,精度提升40% | |
12 | 单方法多调用 | |||
13 | 指令级精度 | 变量关系错误 | 集合类读写 | |
14 | 流敏感性分析,获取运行时关系 | 依赖动态链路刻画 | ||
15 | 动态代码(DRM开关) | 依赖动态链路刻画 | ||
16 | 分析速度 | 调用链越长分析越慢 | 实现论文算法《摘要类建模》,速度提升20%~40% | |
17 | 分析规模 | 分析内容的大小和开销指数级增长 | 分析任务垂直拆分 |
如果要进一步优化准确度可以引入动态代码分析,目前我们也在持续做动态链路刻画和动态代码分析,如果大家有兴趣可以在评论区告诉我。