支付宝移动端混沌工程技术依托于红蓝攻防模式进行全面落地,红军(研发&质量&SRE)构建稳定的系统、应急监控能力,端混沌工程持续注入、挖掘风险异常,相互对抗和提升。支付宝移动端混沌工程的发展分为二个阶段。
第一代,时间2019年到2020年,重点是故障注入体系建设与心智打磨。
第一代端混沌工程主要是注入体系建设与心智打磨。早在2016年,服务端的混沌工程能力已经开始建设,并拉通整个蚂蚁体系进行红蓝对抗的演练。端以此为切入点参与527/1218的大型演练活动中,将整体红蓝对抗的思维在端侧进行形式、逻辑化的能力落地,并以优化客户端体验、减少故障为目标,建立故障注入的体系建设与演练工作。对应用崩溃、小程序崩溃、小程序白屏进行攻击,同时沉淀相关技术及平台,在监控告警、应急快反侧起到了很好的引导效果,同时培养了业务同学的攻防心智,为后续的常态化演练打基础。
第二代,2021年至今,重点是混沌工程风险挖掘体系建设。
第二代端混沌工程主要是在故障注入的基础上,进行更深层的风险挖掘体系建设。端混沌工程初期以模拟故障为主,然而在实践过程中我们发现,挖掘真实的风险,对于整个端高可用有三个方面的好处:一,我们将日常线上的风险问题进行归纳总结,形成可执行的代码规则,再将规则进行整体的横向扩展,挖掘其他场景的真实问题。二,日常风险挖掘出的问题,可以在集成、灰度前进行解决,避免影响范围进一步扩大。三,经典案例库也为高可用领域的527和面向资金安全领域的1218(分别表示5月27日和12月18日,蚂蚁历史上在这两天发生过两次必须铭记的重大故障,不忘教训而取此名)攻防演练提供素材。同时在技术层面,跨端模糊测试组件、变异组件、平行切面、故障注入等硬壳技术逐步归纳,文章后续会逐一介绍。
端混沌工程技术主要有端风险挖掘系统、风险模拟系统和攻防演练系统 三大系统。
通过对客户端历史故障、告警的归因分析,针对高风险的模块进行定向风险挖掘,利用线上真实流量数据作为种子数据,变异出贴近业务语义的脏数据,利用编译器汇编/IR插桩、链接器静态插桩、运行时动态hook等手段,进行自动化 fuzzing 扫雷。
以客户端高可用领域为例,端混沌工程基于运行时hook,对生产环境的业务数据请求进行切面,结合对应业务线的经验以及历史问题归因。例如url、message、data、source等,这些都是常见的交互类型数据,端混沌工程通过对其value进行变异,检测在端侧是否会产生导致端不可用的问题,如不可用问题、卡死、渲染异常等。
端混沌工程经过历史问题分析、变异规则归纳,通过端切面技术截获服务端下发的数据,实时变异数据。发生端侧不可用问题后,截获堆栈信息,结合数据染色技术,将变异规则、数据、堆栈进行绑定。同时上传至服务端沉淀为有价值用例,通过遗传算法不断优化规则。目前种子库沉淀 30+ 规则,共发现 真实风险 600+ 个,可针对 23种 端侧基础设施进行风险挖掘。
顺应新型的业务发展形态,更多的音频、视频、直播场景、酷炫的动画等业务,在支付宝内百花齐放,而这些多媒体组件的底层技术栈往往是基于 C/C++ 语言实现的跨平台方案。此外,端侧还需要一种能够以特定指标,如代码覆盖率变异数据、变异数据、变异流为导向的智能化模糊测试能力。
在此背景下,我们与安全对抗技术团队进行深度合作,基于 AFL++,结合 Fpicker 与 Frida 等端上技术,共同打磨出首个移动端智能化模糊测试方案。同时基于多年专家经验积累,落地了 AntCaseGen。
下面简要地介绍该移动端智能化模糊测试方案的一些实现思路。
从系统层面的角度来说,简要来说,是由三个组件来组成的,分别是 AFL++
/Fpicker proxy
+ Frida agent
。各个组件的关系如下图所示:
而该方案与传统的PC 端模糊测试技术方案中的各个组件存在如下的对应关系:
AFL++
作为 Generator/Mutator
发挥作用。
AFL++
负责模糊测试数据的生成,同时承担了 Generator
与 Mutator
的工作。
同时它需要代码覆盖率的指标来指导其内部的模糊测试数据的生成,从而实现更深层次的模糊测试样本生成。
fpicker proxy + target + harness
对于 AFL++
而言,是一个大的被测目标程序或系统。
从 AFL++
的角度出发,它的模糊测试目标是 fpicker proxy + target + harness
这三者的逻辑组成,但是从系统程序上看,它的模糊测试对象是 fpicker proxy
,它的数据并不会直接输入到 target + harness
中。
fpicker proxy
与 AFL++
之间的数据交互通过 fork-server 内部的 pipe 实现。
fpicker proxy + harness
充当 Coverage Collector
组件。
harness
通过Frida Stalker
能够获取到 BB 粒度的代码覆盖率数据,同时将这些数据回传给fpicker proxy
,fpicker proxy
再将代码覆盖率数据格式化后反馈给 AFL++
,这样就完成了代码覆盖率数据的收集反馈工作,所以 fpicker proxy + harness
整体发挥了传统方案中的 Coverage Collector
的作用。
harness
同 fpicker proxy
的数据交互即可以通过共享内存的方式来进行( harness
与 fpicker proxy
部署于同一系统环境中),也可以通过 Frida
的 Send API
的方式来进行。
frida agent
作为 Fuzz harness
使用。
frida agent
是一份使用 JavaScript 进行开发的 Frida
脚本,它基本充当传统模糊测试技术方案中的 Fuzz harness
的功能,例如准备模糊测试上下文环境,从 fpicker proxy
读取模糊测试输入数据,将模糊测试输入转化为特定的数据结构以满足被测目标的约束。目前frida agent
的模糊测试目标粒度为单一函数。
以上就是该系统的基本的系统组件与对应的能力介绍,在后续的文章中会为大家带来更为详细解读,介绍我们端侧在模糊测试技术应用上,从技术调研到技术落地的过程。
除了内部的主动风险挖掘,外部风险同样是不可忽视的重要环节,对于支付宝这种航母级别的应用,许多能力是对外开放的,在端混沌工程设计初期,我们就开始建立外部风险模拟的能力,尝试跳出支付宝的环境依赖,模拟三方对支付宝客户端发起攻击。
除了蚂蚁业务内部的风险外,外部风险同样不可忽视,例如厂商、运营商、三方服务商的问题对客户端的应急容灾能力提出了更高的要求。
端混沌工程以客户端高可用领域为例,在支付宝中存在大量的三方服务商,其变更次数非常频繁,而挂在支付宝中使得它的稳定性直接影响支付宝。端混沌工程基于运行时hook,收集三方厂商的发布模板,结合变异能力模拟批量的异常发布,导致客户端产生不可用问题。
除三方服务商,端混沌工程还可以模拟系统层面的异常,如通知延迟、文件损坏、耗时任务注入、线程顺序破坏、函数调用破坏等,通过上述手段,检测客户端在高可用领域的容灾能力是否完备。例如端混沌工程通过运行时hook、插桩能力,在冷启动过程中接收一个通知,并在主线程注入一个耗时任务,导致客户端无法正常启动,这时应急容灾必须要找到其耗时的具体位置以及函数,并将其容灾。
端侧故障注入以稳定性、业务不可用、白屏为切入点,基于AOP注入、JS Hook等手段构造故障场景实现攻击,检验业务自身的抗打击能力。通过在端上复现风险挖掘的问题并进行放量来考察业务方。
以小程序白屏为例,首先会启动真机打开小程序,客户端容器会启动 webview 加载基础库的视图层,创建独立线程加载基础库的逻辑层。在视图层进行故障注入主要分三步,1) 源码hook 2) 针对组件事件以及组件事件进行判断 3) 匹配异常注入规则导致视图层 fail进入白屏。在逻辑层进行jsapi的劫持,进而对rpc和request进行重写,导致白屏的出现。出现白屏后客户端会有白屏日志,对白屏日志进行放大触发告警。
选择在基础库层注入两个好处:
在基础库层注入,确保业务源码不受到破坏
注入形式为演练用户,保证攻击过程中对业务无损
对于Native,通过风险挖掘系统的种子可直接作用于故障注入,并结合放量技术,仅用一台设备便可模拟出上千/万级别的故障pv。
在移动端智能化模糊测试技术应用相关项目的立项初期,我们很快就遇到了一些挑战:
既有的移动端模糊测试技术方案基本专注于 Android/iOS 端自身的安全性,例如系统组件与移动端内核等,更专注于 OS 本身的安全性。而对于结合实际业务场景的应用,业内缺乏既有的技术实践方案;
常用的桌面端的技术方案,因与移动端存在系统性差异,导致多数桌面端成熟的技术方案无法直接移植到移动端使用;
移动端的应用软件往往使用了多种语言进行编写,例如 Android 的 Java + C/C++ 的模式,导致了对目标进行模糊测试时,难以对接模糊测试输入与相关的模糊测试上下文;
业务上的移动端应用软件编译环境往往由打包环境进行打包,不便于本地进行测试(测试技术方案是否可行),增加了测试难度,容易产生技术债务;
整体的项目参与人员的能力存在错位,了解模糊测试的同学对移动端理解不深,对移动端了解的同学对模糊测试理解不深,增加了技术实践难度与沟通成本;
对于上面的挑战,我们将问题逐一拆解,逐步将底层能力探索了出来。
首先从 0 开始搭建一个移动端模糊测试方案不论是对于项目本身的落地还是对业务侧的需求满足来说,都是一个时间成本较高的选项。在梳理了项目资源与能力储备之后,我们快速地放弃了从 0 开始搭建的方案,转而把精力投向了已有技术方案的二次开发上。尝试站在巨人的肩膀上,看看能不能再解决一些尚未被解决的问题。
在调研了业内的一些现有方案与技术实践之后,我们发现 fpicker 这一开源项目是比较贴近我们的实际需求的。但是它也和大多数的开源项目一样,具有受众较小的开源项目特有的特点:无人维护且工程化程度较低。即使该项目存在一些难点,在梳理了项目内部的相关技术实现之后,我们仍将其作为一个基础项目,对其进行了能力的拓展,最终得以落地,满足业务侧的需求。
在对 fpicker 项目进行整理、拓展、系统工程化之后,原有项目能力版图上缺失的一块,让整个项目的进度变得极为缓慢 —— 原有项目的代码无法适配 Andorid 平台的底层能力。在 Android 平台上,Google 使用 bionic 这一 C 标准库,并尝试去取代在 PC 端广泛使用的 glibc 库。
这就意味着我们需要对原有的项目剔骨去皮,提炼出它的精华所在,再在 Android 平台上为其做好适配工作。这一过程就如同《封神榜》中太乙真人为哪吒制作莲花化身,其中可谓一步一小坑、三步一大坑。
在完成了 Android 端的适配后,我们在 Android 端与 iOS 端上,对整个系统进行了系统性的测试,完成了多个针对不同目标的模糊测试工作。
在这些模糊测试的过程中,我们关心的目标是系统中的模糊测试数据的流转情况是否符合我们的预期,能否达到模糊测试的目的 —— 发现未知的风险。
而目前系统的的流转流程如下
在系统中,数据的流转流程大体上一共分为九个步骤:
harness
对 exec 信号量上锁
fpicker proxy
从 AFL++
经由 pipe 读入生成的模糊测试输入
fpicker proxy
将模糊测试输入写入 communication map(shared memory)
fpicker proxy
释放 exec 信号量
fpicker proxy
对 iteration 信号量上锁
harness
从 communication map 读入当前的模糊测试输入数据
harness
将当前的模糊测试输入数据送入目标函数进行执行
harness
对 exec 信号量上锁
harness
释放 iteration 信号量,流程回滚步骤 2,继续进行模糊测试工作
那么不断地重复步骤 2 至步骤 9,就能够不断地对被测目标发起模糊测试,并且能够基于代码覆盖率的反馈指标来调整测试样本。
当然,单纯的流程的架构是不足以支撑现有要求的,我们还需要更强大的底层模糊测试库,就是上文中提到的AntCaseGen。
AntCaseGen 是一款畸形数据生成引擎,负责模拟生成外部风险及畸形脏数据,起到承上启下的作用,内置了大量Fuzzing变异算法、规则和样本库,同时我们可以将专家变异经验、线上问题归因分析,录入至平台中并最终形成一条变异能力。再将此变异能力与客户端的业务做紧密连接,结合百万级别的畸变样本,更轻易地发现隐藏问题。
同时还改变了专家与模糊测试项目之间的强耦合关系,对于业务侧而言,能够快速地通过 AntCaseGen 的 SDK或者开放的HTTP接口,依照自身地需求接入相关的能力,以满足自身的需求,而不需要与专家背靠背来进行相关能力的建设。
下图是简要框架图框架:
AntCaseGen 底层依赖 AntFuzz 系统在实际的业务场景中积累的大量模糊测试资产,如畸形样本库和各类模版库,业务方可以根据场景灵活选用。目前畸形样本库的样本数量为百万级别。
AntCaseGen 能满足常见的业务调用场景(如客户端调用、服务端调用),且满足跨语言支持,对不同的语言环境都能通过相应的 SDK 或者HTTP接口来进行服务调用,接入难度与成本都较低。
AntCaseGen 同时还提供了变异数据留存和查询的能力,能够根据调用时间和 hash id 来获取到唯一、确定的导致异常的畸形数据,便于业务自行进行复检:
AntCaseGen 在多个不同的优势如下:
能针对 复杂结构的数据 进行智能化的安全测试;
能在 复杂场景 中便利地加入安全测试能力;
内置大量变异引擎、算法和数据,能满足各类数据变异需求;
支持跨平台、跨语言的 SDK 调用或者 HTTP API 接口调用;
能相当程度地 丰富 已有的测试用例,增加测试的广度与深度;
能够用于压测中畸形流量的生成,也可用于流量攻击测试。
以一个场景为例,AntCaseGen 支持对自定义结构数据的变异,通过类C语言+内置标签的方式描述协议或复杂数据的 raw 格式,针对性地生成相应的变异数据。
其描述语法的示例如下:
struct _start_ {
uint24 len;
uint8 seq;
uint16 client_cap;
uint16 ext_client_cap;
int max_pkg;
uint8 charset;
char unused[23];
char username[5];
char plugin[22];
char conn_attr[len-2-2-4-1-23-5-22];
}
#max package_size 1024
#type mutator "boundary"
#fix _start_.seq 1
#fix _start_.charset 33
#fix _start_.username "root\x00"
#fix _start_.plugin "mysql_native_password\x00"
#range _start_.len (40..1024)
AntCaseGen 会根据该描述随机地生成符合该结构的原始数据(二进制流),供调用方进一步地使用。
除自定义的结构外,还支持 结构化数据变异(json等),正则表达式变异、畸形HTTP流量生成、畸形数据样本自动化获取等能力,具体见《AntCaseGen 介绍》 。
混沌工程将风险挖掘系统、红蓝攻防等能力,通过产品化的形式进行融合,沉淀为蓝军工作台。提供自闭环的产品体验,可以配置简单的参数进行定向风险挖掘,产出风险后直接作用于攻防演练,下文着重介绍此平台。
蓝军工作台的源起还要回溯到2019年 石器时代( -> 如今 青铜器时代),端混沌工程的初期大量的人力浪费在环境部署、案例分散存储、演练手动触发等 - 石器时代。随着自动化能力的沉淀、更多的风险案例被暴露出来,蓝军小组将整体方案进行串联且落地为一个专项平台,蓝军工作台应运而生 - 青铜器时代。
蓝军工作台打通云测平台、告警平台,通过简易的操作即可完成一次攻防演练。在实践中,端混沌工程工作台具备攻防演练、风险挖掘的闭环能力,每日针对重点业务场景的自动化风险挖掘,案例与攻防演练打通,且实时推动业务进行缺陷修复,提升整个端高可用。
下面是整体平台的架构设计,端混沌工程将风险挖掘 与 攻防演练能力打通,实时的风险案例存储不仅可以进行攻防演练,还可看到端上的存量风险状况
风险挖掘是其中重要的环节,在平台侧,只需要键入些基本入参(页面、挖掘类型、账号)便可以很方便的进行挖掘,平台给使用者达到最优体验,全程自动化完成,等待半小时便可直接查看挖掘结果。下面是风险挖掘的结果展示,有复现链接、变异规则、不可用问题堆栈等数据,可以直接新增一个攻防演练的案例
图中可以看出,挖掘出的闪退会将堆栈携带上报,同时带上页面信息、变异规则、页面详情等信息,通过新增案例按钮便可新建一个攻击Case,并随时抽调出来进行一次演练
攻防演练也是自动化的模式,可选择提前设定好的攻击案例进行任务的触发,可以设定预期闪退的量级,支持1-N次的设置
上图是触发一次攻防演练的截图,自动化的过程中会实时上报攻击状态、当前量级,底层自动化能力对接云测平台(支付宝自研)进行真机实时攻击操作,且利用模拟放量 + 用户ID模拟的能力,达到以假乱真的目的。
最后,将整体的一次攻防演练化为下面的链路图形式,从任务创建->执行攻击->结果展示,一共需要11步,其中70%的底层能力全部自动化实现,只有攻击任务创建、应急、容灾处理需要人为参与。
端混沌工程项目,从最初的模拟攻击,到如今真实风险攻击->风险挖掘体系化,技术架构升级带来的收益是空前的,同时也给我们的技术远行带来了足够的信心,总结共有以下几条关键点:
通过对线上异常、告警的归因分析,沉淀几十条高价值异常模拟能力,多数场景可以复用于挖掘其他相同业务场景异常,带来了1 : N的收益
端混沌工程通过平行切面、Mock、闪退信息染色、异常复现路径绑定、模糊测试基建、FUZZ库、故障注入等技术手段不断对风险挖掘体系添砖加瓦
在非稳定性问题领域,如业务不可用、渲染异常、隐私合规战场同样有风险挖掘的影子,并参与到红包、端大型活动中,发现几十例问题并全部解决。在不可用层面突破了文字重叠的自动化检测能力,目前可支持双端+h5的自动异常识别
整体的体系化思路也带来了不错的业务收益,联合精细化管控作用于Config、Lottie、Cube三大变更源,目前Lottie所有变更源已经全部完成对接,成功防御潜在故障17次,同时Config、Cube在稳步接入中
与安全对抗技术团队的合作,将风险挖掘体系的技术能力,再次拉高了数个档位
fpicker blog
fpicker repository
AFLplusplus repository
Frida release page
Firda - stalker
不溯、艾许、超六、流泉 来自支付宝技术部。
如对本文有任何建议或问题,请关注我们的微信公众号,我们将私信回复 ❤️