饿了么资金安全:9秒完成一次注入演练

原创
2023/12/27 08:30
阅读数 32

阿里QA导读:资金安全中基于DB字段异常的演练是一个让人又爱又恨的事情,饿了么的测试同学进行了一个非常高效的实践:自动生成脚本、自动注入服务器、自动发起流量,将2小时的演练工作,缩减到9秒。

前言

资金安全一直是质量的一个重要课题,如果说监控、核对、值班机制、应急手段是防控的重器,那么资损演练就是检验这套重器的核心手段。


演练是一个让人又爱又恨的事项,爱是因为有效,通过人为引入某个DB字段异常,测试核对、监控发现数据异常的能力;恨是因为低效,每个字段都涉及场景、编码、调试等大量工作。


很多团队都建设了一套相对标准的量化方案:基于核心应用的DB字段打标,标记出存在资损风险的字段,并以此作为演练覆盖的目标。由此,不难得出两个指标:DB字段打标率、演练字段覆盖率。在提升覆盖率上,我们花费了大量的精力,究其原因,在于需要演练的字段很多,但是演练的方法没有跟上。


我们做了一个简单的统计,一次演练包含了确定字段、设计场景、阅读代码、编写注入脚本、调试脚本、执行注入,最终达成篡改字段的效果,平均时间在100分钟上下。

目标

9秒,完成一次资损演练。

将近2个小时的工作,缩减到9秒,就需要从“确定字段”直接到“篡改字段”。简单来说,就是抽象出通用手段,完成自动生成脚本、自动注入服务器、自动发起流量,全程用户无感知。

效果演示

案例:小西作为系统测试owner,计划对某个DB资损字段进行演练。在此之前,她已经把该系统“一键入驻”到 VIP平台。于是,演练过程,将如视频所示。


最终指定的DB字段从原来的:200000000000167245篡改为 200000000000167247,而上下游系统的数据均不变,成功注入数据异常场景:


方案

一键演练 = 自动规则+ 自动流量


名词解释:

  • 资损演练:完成一次完整的DB字段注入。

  • 一键演练:“一键”完成一次完整的DB字段注入,包括:创建注入脚本、下发到服务器、发起对应的E2E流量。

  • 自动规则:自动动创建注入脚本、自动下发到对应的服务器。

  • 自动流量:根据指定的DB字段,找到会写入该字段的E2E自动化用例,并执行

架构设计

架构设计分为三个功能域:基础域、准备域和执行域,能力承载的应用是VIP(一站式验证平台)。



基础域,提供通用能力,重点包括:应用管理、权限管理、规则管理、容器管理、统计报表等。


准备域,是一键演练的非常重要的部分,主要分为三块内容:

  1. 应用、库表和字段信息。vip通过alsc-risk获取字段信息、资损打标信息并保存,同时保持定期更新;

  2. 应用与用例关系。vip通过kbt获取指定应用的用例信息,保存并定期更新;

  3. 字段和用例的关系。vip执行指定用例集,并通过特定的vip-agent采集能力,采集用例在指定应用中insert 和update的字段,获取到用例和字段关系,并建立字段到用例的映射信息。具体的细节会在后续的“一键入驻”章节介绍。


执行域,是一键演练的核心部分,主要有四块内容:

  1. 预备模块,提供了vip-agent的安装功能、mybatis容器的安装功能(容器的作用,会在后续介绍);

  2. 脚本模块,提供了自动创建规则、自动下发规则的能力;

  3. 流量模块,提供了通过指定字段,过滤出合适用例,并调用kbt执行的能力;

  4. 事后模块,提供了结果处理、结果轮询、现场清理的能力。


后面就大家可能最感兴趣的两个核心模块:自动生成规则、自动发起流量进行深入介绍。

说明:

从上面的架构设计不难看出,目前VIP跟kbt用例平台对接,实现了用例与应用、用例与字段的关系建设,以及用例执行等功能,这也代表着,“自动发起流量”目前只支持kbt的用例。

自动生成规则

用户指定一个DB字段(含应用名、库表名、字段名),VIP直接生成一个注入规则,此功能需要具备通用性,适用于多个系统。


方案由两部分组成:mybatis 规则容器,一套统一的基于DB字段的规则语法。

mybatis 规则容器

VIP通过锚定一个Mybatis 公共包的底层函数,来解决往常的每次注入都要在应用代码中,找到不同的函数、编写不同的注入脚本的难题。同时VIP需要在容器中实现几个核心能力:

  1. DB字段到DO模型属性的映射;

  2. 统一DB字段的规则语法解析与转换;

  3. 篡改规则管理,含创建、生效、暂停、失效、删除等;

  4. 容器通用能力:缓存、计数、上报、清理等。




VIP锚定的函数是:org.apache.ibatis.session.defaults.DefaultSqlSession#update(java.lang.String, java.lang.Object)

统一的DB字段的规则语法

VIP定义了一个三段式的语法:

  • 流量过滤,关键词:filterTraffic

  • 字段过滤表达式,关键词:filterEquation

  • 字段处理表达式,关键词:processEquation


其中,流量过滤可以区分出kbt流量、doom流量、万象流量、影子流量等,同时也支持定制化的流量标签,从而保证DB篡改可以跟自动化等流量区分开。


字段过滤表达式、字段处理表达式,均包含三部分:变量,操作符,值。与之对应的关键词:property, operation, value,具体的含义如下表所示。


filterEquaiton -- 过滤方程式


key

说明

可填值

property

表的字段名称

表字段名,例如:buyer_amount

表字段名.[json串路径],例如:ext.itemInfos[0].price

operation

定制好的表达式

equals : 等于

not_equals : 不等于

contains : 包含

not_contains : 不包含

value

目标值,String类型

例如:“123”,“0.1”,“wait”

processEquation - 处理方程式


key

说明

可填值

property

表的字段名称

表字段名,例如:buyer_amount

表字段名.[json串路径],例如:ext.iteminfos[0].price

operation

定制好的表达式

assign : 赋值

随机化,可指定区间:int_random、double_random、long_random

金额操作:amount_plus_1_cent 等

日期操作:date_minus_1_day 等

value

目标值,String类型

赋值,例如:“123”,“0.1”,“wait”

随机化,~ 间隔。例如:“1~3”,“0.01~0.03”

其它,同赋值场景,例如:“14400”,“0.3”

案例

依旧以上面小西的演练场景为例,同学在页面中点击“一键演练后”,VIP获取到的信息:应用alsc-rights,表alsc_right_template,字段ele_right_template_id。最终生成的规则如下:


{

  "filterTraffic": {

    "attributes": {

      "e2e_task_type": "assets",

      "e2e": "1"

    },

    "type": "eagleeye"

  },

  "filterEquation": [],

  "processEquation": [

    {

      "property": "ele_right_template_id",

      "operation": "int_plus_1"

    }

  ],

  "tableName": "alsc_right_template"

}


说明:

  • filterEquation为空,表明没有过滤条件;

  • processEquation,包含了篡改的字段名="ele_right_template_id"、篡改的策略是“int 数值加1”;

  • tableName,代表表名;

  • filterTraffic,是基于流量上下文的过滤,本案中表示:基于鹰眼(type : eagleeye)上下文,过滤userdata中 e2e_task_type = "assets"且 e2e="1"的流量,才进行篡改。


由于篇幅关系,更多实现细节不在这里展开。

自动发起流量


用户指定一个DB字段(含应用名、库表名、字段名),VIP选择对应的E2E自动化用例(用例会写入指定的DB字段),并在指定环境执行用例。


这里需要处理几个关键问题:


首先,E2E用例是有归属团队的,而且绝大部分用例在执行过程中都会跑到多个域。例如:外卖下单用例,经过了交易域、营销域、服务库、支付域,再到商家、物流等,共计大几十号应用。当支付域的同学做演练时,VIP就不能随意选择一个归属于交易团队的用例当做流量。


其次,VIP需要保证选中的E2E用例,一定会在用户指定的应用,写入指定的DB字段。


方案由以下四部分组成:

  1. 建立应用与实验室的关系;

  2. 运行实验室,并通过vip-agent采集每个用例在指定应用上,insert/update的DB字段;

  3. 基于采集到的信息,建立字段到用例的关联关系;

  4. 基于字段,对关联用例集做有效性排序(指标为:用例近期运行的次数和成功率)。


重点介绍一下第二点:采集用例和DB字段的关联关系。原理比较简单,在目标应用服务器中开启vip-agent采集能力,然后执行E2E实验室,流量经过目标服务器后,agent记录下用例、表、字段的关系,并异步上报给vip-prod。


完成以上采集和上报信息功能的是mybatis采集器,它是一个基于mybatis容器开发的模块。为了更容易理解采集器、容器、agent三者关系,我将vip-agnet整体的架构放在下面:


简单来说,mybatis采集器的核心能力是:过滤、收集、缓存、上报、清理。

  • 过滤:依据配置,过滤流量;

  • 收集:解析流量,获取到字段或值,并保存在本地;

  • 缓存:缓存管理和保护机制;

  • 上报:定义报文上报给prod,以及异常处理;

  • 清理:缓存清理策略。



补充:建立应用和kbt实验室的关系,一个有趣场景。

我们知道应用是有归属团队的,这个信息在aone可以查到;同时,实验室也是有归属团队的,在kbt可以查到。但是,有趣的地方是,kbt上的组织结构是用户自己填写的,这就跟aone上的信息会存在较大的差异。例如:应用alsc-trace-center,在aone上,归属于:业务中台/交易平台,对应的kbt实验室规则属于:平台技术部/交易质量组。再如,aone:销售网络/供给平台",对应于kbt:供给技术部/销售作战质量组等等。

此处采用的方案是分词和文本相似度计算:HanLP分词、Jaccard相似度&余弦相似度结合。可以直接是Apache Commons Text库,效果不错。

产品核心能力设计

上面一个章节主要从底层能力拆解的角度进行了介绍,本章节会从产品设计的角度,重点介绍几个核心场景及其背后的流程。

一键入驻

一键入驻,就是在用户指定应用后,VIP后台去建立所有一键演练需要的所有信息的过程。设计的原则是极简--用户只需要一次点击。


页面设计:



点击背后的调用流程:


之后,就完成了架构设计章节中,提到的“准备域”的工作内容。应用和库表的关系除外,这部分是VIP后台任务定期从alsc-risk平台获取。


一键演练

在本案设计之初,我们就确定了要把所有演练过程集中在“点击一下”这个动作上


VIP有了本文阐述的上面的所有能力和必要信息后,点击一下就变得非常的简单:

  1. 用户点击按钮,背后是传入的:应用名、库表名、字段名;

  2. prod层基于输入,创建统一的DB字段篡改规则;

  3. prod给应用服务器安装agent、mybatis容器、篡改规则;

  4. prod过滤出关联的E2E用例,调用kbt执行用例;

  5. prod等待agent 上报篡改成功的信息,并清理环境;

  6. prod本地任务巡检,如果超时没有上报,则直接清理环境。



至此,我们就实现了一键演练这个核心功能。当然,实际情况会更复杂一些,例如,因为应用服务器往往是多台,所以prod要做协同等。篇幅缘故,不再赘述。


补充,“一键演练”旁边的“一键注入”是什么功能?

一键注入,其实是“现实的骨感”,我们目前还有很多字段是没有kbt用例覆盖的,那么这些字段就无法实现“自动流量”。但是,这并不阻碍实现“自动规则”,也就是自动生成规则、自动安装agent&容器&规则到服务器,然后等待用户手工发起流量,后续的流程跟一键演练一样。



Finally:点击“一键演练”,喝杯水



当然,在点击“一键演练”之前,你需要在平台上找目标应用、目标库表,实现的逻辑比较简单,不再展开。

好奇一问



关注阿里巴巴技术质量阅读更多





本文分享自微信公众号 - 阿里巴巴技术质量(AlibabaTechQA)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部