FunProxy - 使用 Rust 构建跨平台全链路测试抓包代理工具
作者:vivo 互联网大前端团队- Song Jiachao
在软件开发过程中,软件测试对于保障软件质量和用户满意度起着关键作用。为最大程度上提升软件品质,我们积极开展全链路测试实践,打造了用 Rust 语言开发的自研一站式抓包代理工具 FunProxy,基于其跨平台、高性能、易于扩展、安全性高等特性,让全链路抓包和环境代理如丝绸般丝滑。
一、背景介绍
1.1 什么是全链路测试
全链路测试就是“验证整个软件系统在不同组件、服务和模块之间协同工作时的性能、功能和稳定性”。在这里我们举一个非常简单的例子。
比如用户在某商城购买商品。

我们是先打开商城,接着浏览商品,加入购物车,然后提交订单,支付,等待收货,最后完成。在整个购买流程中,我们其实并不是一个功能模块就完成全部步骤,而是调用了很多系统模块。
比如:
全链路测试就是验证一个流程中所有涉及的系统,协同工作时的性能、功能和稳定性。
1.2 全链路测试的现状和痛点
通过上面的购物流程我们可以梳理出全链路测试的现状和痛点:
1. 系统数量众多
全链路测试涉及到多个系统、服务和模块的协同工作,系统的多样性增加了测试的复杂性。
2. 各系统环境配置不一致
各个系统的环境配置可能完全不一样,导致各个系统对接相当麻烦。

就拿我们刚刚所举出用户购买商品的例子。涉及到商品系统、购物车系统、订单系统、支付系统、和物流系统。因为历史或者技术方案的原因,他们选择的环境管理方式各不相同。
其中商品和购物车系统可能是由团队 A 负责,他们团队通过 hosts 方式来管理环境。
订单和支付系统,由团队 B 负责,通过自定义请求头的方式,来进行环境配置。
物流系统由团队 C 负责,通过域名的方式来配置环境。
这只是精简版的购物流程,其真实情况可能远比我们的例子更加复杂。这时候如果想要完整的测试一条购物全流程,环境配置还是相当复杂的。
当前测试流程
为了能够测试所有的流程:
要安装一个抓包软件
安装抓包软件的证书
配置各种抓包的规则
配置抓包的系统代理
配置 hosts
配置终端(安装证书、设置手机代理)
这一套流程下来其实需要配置的非常复杂,并且不能共享,每个人在自己的电脑和手机上都需要重新配置一遍。

二、全链路测试的愿景及目标
因为上述背景,我们对 vivo 的全链路测试提出以下的愿景和目标。
我们的愿景是:让 vivo 的全链路抓包和环境代理,如丝绸般丝滑。
我们的目标是:构建一款跨平台、高性能、易于扩展、安全性高的全链路测试抓包代理工具。

2.1 技术目标详解
跨平台
能够支持几乎所有主流平台,包括但不限于 Windows/macOS/Linux/Android/iOS,为什么要兼容这么多平台,因为我们的业务在这些平台上面几乎都有涉及。
高性能
面对超高并发量的接口请求,能够轻松应对,确保系统在高负载下的稳定运行。
易拓展
提供灵活的架构和工具,支持官方和用户根据个人需要对工具进行拓展。
安全性高
通过全面的安全测试,确保产品在各个层级的安全性,包括数据传输、存储和访问控制,防止潜在的安全威胁和数据泄露。

三、技术选型
3.1 为何选择 Rust
我们首选了 Rust 语言作为我们的基础语言,主要原因如下:
Rust 是系统级别的通用编程语言,上至 web 下至 OS 统统能轻松驾驭,并且能够保证内存安全和并发安全;
Rust 有丰富的工具链,比如 rustup,cargo 等等,开发体验非常棒;
Rust 有非常庞大和活跃的社区,社区贡献了非常多好用的各种库。
并且最近使用 Rust 构建应用的公司越来越多,比如我们公司的 Blue OS ,就是行业首个系统框架由 Rust 语言编写的操作系统,这也是我们坚定不移的选择 Rust 的重要原因之一。

3.2 为何选择 Tauri
选择了 Rust ,我们顺其自然的选择了 Rust 多端开发框架 Tauri。Tauri 是一个基于 Rust 构建的跨平台应用框架。
主要有以下几个优势:
独立的前端工程:Tauri 支持任何前端框架,所以你不需要改变你的技术栈;
最小化体积:使用操作系统本地的网页渲染器,Tauri 应用的体积可以达到最小 600KB;
跨平台:同一套代码可以编译运行到几乎所有的 OS 系统中;
高安全性:Tauri 团队的首要目标,推动 Tauri 的首要任务和最大的创新。
进程间通讯:用 JavaScript 编写前端,用 Rust 编写应用程序逻辑,并使用 Swift 和 Kotlin 在系统中深入集成;
由 Rust 驱动:以性能和安全性为中心,Rust 是下一代应用程序的语言。
使用 Tauri 框架,让我们不仅能获得 Rust 的安全性和高效性,还能享受 Web 开发的熟悉感和灵活性。

四、方案介绍
通过刚才的技术方案,我们打造出了 FunProxy 一站式代理工具。FunProxy 是一款用 Rust 开发的纯自研的一站式抓包 & 代理工具,全平台支持,天生更安全,天生更流畅!!!
主打一个方便、快捷和无边界。

4.1 优势及亮点
FunProxy 主要的优势及亮点如下:
全功能抓包能力
全平台独立应用支持
云端 hosts
云端 Rules
协同抓包
极致性能

4.1.1 全功能抓包能力
协议
支持 HTTP/1.x 和 HTTP/2 协议、WebSocket、TLS 1.1-1.3 的加密协议
工具
支持重写、断点、数据对比、模拟超时、全局搜索、筛选、对比
文件
支持导入导出会话、支持 Fun 格式的文件,HAR 格式文件、Charles 格式文件

4.1.2 全平台独立应用支持
我们支持几乎所有的主流操作系统,例如 Windows/macOS/Linux/Android/iOS/还有网页版本,并且多操作系统可以相互配合,FunProxy 让代理打破边界。

4.1.3 云端 hosts
hosts 维护是一个大的痛点,因为各个系统的 hosts 会经常变化,导致有些同学的 hosts 因为没有及时同步变更,而出现问题。所以我们提供了云端 hosts 功能。云端 hosts 可以让项目中的 hosts 由一人设置,人人共享。保证 hosts 能够实时同步到 FunProxy 的各个用户。
云端 hosts 支持静态和远程两种 hosts。
静态 hosts:系统中的 hosts 文件格式一样,一一对应。
远程 hosts:可以提供一个链接,我们会远程去拉取这个 hosts,在 FunProxy 运行的时候再去加载这个 Hosts。
顺便说一句:FunProxy 所有的 hosts 都是虚拟 hosts,并不会修改系统 hosts,保证系统 hosts 的干净

4.1.4 云端规则
同云端 hosts 一样,规则也可以配置到云端让所有人共享。

所有的规则都有一些公共的配置。比如规则名称、匹配模式和匹配链接。
我们的匹配模式支持通配符和正则表达式。几乎可以适配所有的链接。
同时我们也提供了检测工具,帮助大家检测链接是否被匹配上。

目前规则主要有三个分类:分别是远程映射,本地映射,和解密。
远程映射在远程映射这个功能上,我们可以配置远程主机的相关信息,这样就可以将需要转发的链接转发到对应的服务器上面。
本地映射在本地映射模式中,支持直接修改本地映射的内容,同时我们提供了强大的代码编辑器功能,帮助大家在编写本地映射内容的时候, 能够有比较好的代码提示。
解密功能这个功能对于很多加密传输网站测试尤为重要。因为每个网站的加解密方式可能不一样,所有我们提供了运行时函数。用户可以自己编写 JavaScript 或者 Python 运行函数,动态的根据传入的参数进行对应的加解密计算。
动态函数解析让 FunProxy 几乎能解所有的密文,这样我们在查看接口的时候就非常的方便,不用再去解密工具中查看。
同时也请大家放心,我们的解密工具有着非常高的安全性,保证只有项目管理员授权的人才能查看,大家也不用担心自己的解密方法被别人盗取。

4.1.5 协同抓包
通过 FunProxy 左下角提供的分享功能,可以让当前抓包的所有数据实时同步给所有拥有这个链接的人。所有的操作都能同步到所有端,无需下载,让大家更加方便的进行数据包的共享。

4.1.6 极致性能
我们对比了市场上主流的抓包软件,无论从安装包大小、启动时间、安装空间、使用内存来说,FunProxy 都有非常大的优势。

4.2 技术架构
FunProxy 是基于 Tauri 框架进行跨平台的开发,我们封装了 fun-core 和 fun-mitm 两个核心库。
fun-core 主要是所有端的公共能力,比如配置文件,存储等。
fun-mitm 主要负责所有端的 man in the middle 也就是中间人的功能,提供抓包的核心能力。
tauri-plugin-funproxy 因为有些端的功能可能需要调用系统特定的能力,在移动端我们封装了 tauri-plugin-funproxy 来调用移动端的特定能力,比如 VPN。
其他在各个桌面端我们封装了各个系统的核心 crates 来调用桌面端的特定能力。其他能力则是通过 Rust 直接调用。
为了提供云端能力,我们使用 Go 语言搭建了一个服务。包括:项目管理、用户管理、升级管理、健康检查、云端 Host、云端规则、云端工具等等功能。服务只是一个增值功能,所有的 FunProxy 都可以离线运行。
同时为了保证各端 APP 核心能力的正常,使用了 playwright 搭建了自动化测试能力。重点测试的功能有:登录、代理、抓包、升级、权限、兼容性、性能等。
最后通过 vitepress 搭建 FunProxy 的文档功能。方便用户使用和查看。包括:介绍、使用说明、常见问题、更新日志、API、贡献指南、问题反馈等。

五、核心实现
5.1 MITM
这是 FunProxy 的 MITM(Man-in-the-Middle,中间人)方案。所谓的中间人,就是在服务端和客户端之间加入一个节点,这个节点负责接收客户端发送的内容,通过自己的规则然后再转发到服务端。我们这里用 HTTP 和 HTTPS 举例:

HTTP 中间人方案:
客户端通过发送 HTTP 内容到 FunProxy,FunProxy 拿到 HTTP 内容后,在转发到服务器中。服务器处理完成后再将信息发送给 FunProxy,FunProxy 在转发给客户端。这就完成了一个请求的中间人接收和转发方案。
由于 HTTP 都是明文传输,所以比较简单。HTTPS 就比较复杂了,涉及到 SSL 证书的认证,具体的大家可以看图上的流程。
了解完了中间人的过程。下面我们根据刚才分析的过程,可以设计出 Fun-MITM 的模块需要包含哪些模块。
CA 模块:负责根证书的生成和加载,以及各个网站证书的认证
Client:这个 Client 就是模拟真实用户发送请求的那个客户端
Server:这个 Server 就是拦截用户请求的那个服务端
http_handler:更改请求和响应的内容
socket_handler:处理 socket 请求

5.2 虚拟 hosts
在中间人方案中如何实现虚拟 Hosts 能力?我们在定义 client 的时候,可以定义一个 resolver。这个 resolver 在每次 hosts 解析的时候都会调用。
首先他会去云端获取当前 hosts 的配置的 IP 是哪个,如果有的话,直接返回。如果没有配置,那么调用系统的 loopup_ip 函数来直接解析 hosts。最后将解析好的 hosts 返回。
在定义 HttpConnector 的时候,使用 new_with_resolver 加载这个 dns-resolver。这就完成了一个简单的自定义 dns-resolver。

5.3 自动安装证书
在使用 FunProxy 中可以自动安装并设置证书为信任。具体的是在 macOS 中调用 security add-trusted-cert。在 Windows 中主要调用 certutil 方法具体的命令行和 rust 代码如图片所示:

5.4 流量拦截
接下来给大家分享一下我们是怎么拦截流量的。首先是 PC 系统,比如 Windows/macOS/Linux 这些系统上,APP 授权后可以获取很高的权限,所以我们直接调用系统提供的接口能力。

比如在 macOS 上面就是通过 networksetup 这个命令行工具实现对系统代理的设置,在 Windows 上面可以通过 ProxyServer 设置。


而在移动端 APP 上面,一般 APP 的权限特别低,APP 没有直接设置系统代理的能力,所以我们采用的是通过 VPN 的方式来实现流量的拦截与转发。
我们通过 VpnService 来创建 VPN 服务。然后调用 VpnService 的各种能力。
这里我们用了一个安卓 Vpn 的 setHttpProxy 方法,就可以将所有的流量主动打到我们的 fun-mitm 服务器上面。fun-mitm 在通过自己的规则对所有的流量进行处理,包括 DNS 解析或者请求响应的修改等等。

5.5 调用系统能力
我们以 macOS 应用沉浸式头部为例给大家做个分享。在 macOS 应用设计中,其实更加通用性的设计是沉浸式的头部,而 Tauri 生成的应用,默认都会有一个头部,如屏幕上黄色所示,这个头部其实没多少作用。接下来我将用这个例子,给大家分享一下在 Rust 中如何通过调用系统的原生的能力,来去掉这个头部。

我们通过 cargo new macos --lib 创建一个 lib 库。在 lib 库中新建一个 window.swift 文件,主要使用 window.titlebarAppearsTransparent 方法来设置透明度。
接着在 lib 中通过 swift_rs 中的 swift 宏来调用这个函数,并将这个函数设置为 pub 给其他方法调用。
给这个 lib 添加 build.rs 来编译这个库。可以指定 macOS 的版本等其他内容。最后我们在自己的项目中就可以直接引入这个 lib 库。直接调用里面的 set_titlebar_style 方法。从而通过 swift_rs 调用 macOS 中的原生能力。

5.6 协同抓包
协同抓包能够让一端的抓包数据,通过链接分享的方式,实时同步给其他所有拥有这个链接的人。
主要核心是我们的 fun-core 这个库。通过 fun-core 这个库启动的时候我们会启动两个服务,一个是 api,负责接口服务。
另一个就是会启动 websocket 服务。用户打开分享过来的链接,会自动通浏览器的 websocket 方法来直接对 fun-core 的 websocket 进行通讯。当有新的抓包数据产生的时候,fun-core 会通过 websocket 推送给所有当前连接的用户。从而达到一端抓包,多端同步的功能。

六、规划总结
6.1 规划
接下来我们重点投入的是 workflow 这个功能,支持对请求响应的全生命周期管理。用户可以直观的选择想要的工具,并构建工作流对请求响应进行处理。工作流不仅支持请求响应的处理,还支持逻辑的判断,比如将符合某种条件下的请求高亮显示出来。等等,可玩性更高。

6.2 总结
通过上面我们对 FunProxy 的介绍,相信大家对 FunProxy 有了比较不错的了解。FunProxy 使用 Rust 构建的跨平台全链路测试 &抓包代理工具。通过 FunProxy,我们只需要简单的通过选择,比如选择项目,选择环境,选择规则,就能将全链路测试过程中复杂的配置流程,变得异常的简单。同时通过云端功能让所有人能够共享配置,极大的提升全链路测试的环境配置和抓包效率,让全链路测试变得更加丝滑流畅。
版权声明: 本文为 InfoQ 作者【vivo互联网技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/0a656f2a70cb67660190b85a4】。文章转载请联系作者。
评论