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_handker:处理socket请求
let mitm = Proxy::builder()
.with_addr(addr)
.with_client(client)
.with_ca(ca)
.with_http_handler(custom_handler.clone())
.with_websocket_handler(custom_handler.clone())
.with_graceful_shutdown(async {
close_rx.await.unwrap_or_default();
})
.build();
pub struct WantsHandlers<C, CA, H, W, F> {
al: AddrOrListener,
client: Client<C, Body>,
ca: CA,
http_handler: H,
websocket_handler: W,
websocket_connector: Option<Connector>,
server: Option<Builder<TokioExecutor>>,
graceful_shutdown: F,
}
impl<C, CA, H, W, F> ProxyBuilder<WantsHandlers<C, CA, H, W, F>> {
/// Set the HTTP handler.
pub fn with_http_handler<H2: HttpHandler>(
self,
http_handler: H2,
) -> ProxyBuilder<WantsHandlers<C, CA, H2, W, F>> {
}
/// Set the WebSocket handler.
pub fn with_websocket_handler<W2: WebSocketHandler>(
self,
websocket_handler: W2,
) -> ProxyBuilder<WantsHandlers<C, CA, H, W2, F>> {
}
/// Set the connector to use when connecting to WebSocket servers.
pub fn with_websocket_connector(self, connector: Connector) -> Self {
}
/// Set a custom server builder to use for the proxy server.
pub fn with_server(self, server: Builder<TokioExecutor>) -> Self {
}
/// Set a future that when ready will gracefully shutdown the proxy server.
pub fn with_graceful_shutdown<F2: Future<Output = ()> + Send + 'static>(
self,
graceful_shutdown: F2,
) -> ProxyBuilder<WantsHandlers<C, CA, H, W, F2>> {
}
/// Build the proxy.
pub fn build(self) -> Proxy<C, CA, H, W, F> {
}
}
5.2 虚拟 hosts
在中间人方案中如何实现虚拟Hosts能力?我们在定义client的时候,可以定义一个resolver。这个resolver在每次hosts解析的时候都会调用。
首先他会去云端获取当前hosts的配置的IP是哪个,如果有的话,直接返回。如果没有配置,那么调用系统的loopup_ip函数来直接解析hosts。最后将解析好的hosts返回。
在定义HttpConnector的时候,使用new_with_resolver加载这个dns-resolver。这就完成了一个简单的自定义dns-resolver。
let resolver = tower::service_fn(move |name: Name| async move {
let ip_option = host::get_ip(name.as_str());
match ip_option {
Some(ip) => {
let ip: IpAddr = ip.parse().unwrap();
host::add(name.as_str(), ip.to_string().as_str());
Ok::<_, Infallible>(iter::once(SocketAddr::from((ip, 80))))
}
None => {
let sys_resolver = Resolver::from_system_conf().unwrap();
let future = spawn_blocking(move || {
let lookup_ip = sys_resolver.lookup_ip(name.as_str()).unwrap();
if let Some(ip) = lookup_ip.iter().next() {
host::add(name.as_str(), ip.to_string().as_str());
Ok(SocketAddr::from((ip, 80)))
} else {
Err("No IP address found")
}
});
let addrs = future.await.unwrap().unwrap();
Ok::<_, Infallible>(iter::once(addrs))
}
}
});
let mut http_connector = HttpConnector::new_with_resolver(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,我们只需要简单的通过选择,比如选择项目,选择环境,选择规则,就能将全链路测试过程中复杂的配置流程,变得异常的简单。同时通过云端功能让所有人能够共享配置,极大的提升全链路测试的环境配置和抓包效率,让全链路测试变得更加丝滑流畅。
FunProxy - 使用 Rust 构建跨平台全链路测试抓包代理工具的更多相关文章
- 安全测试 - 抓包工具BurpSuite
Brup SuiteBurpSuite是用于攻击web应用程序的集成平台.它包含了许多工具,并为这些工具设计了许多接口,以促进加快攻击应用程序的过程.所有的工具都共享一个能处理并显示HTTP消息,持久 ...
- 拥抱小程序,WeTest小程序全链路测试解决方案正式上线
背景 随着微信开放小程序开发功能,迅速在各个实体店抢占流量入口,广大商家看到了在线和离线的机会整合,利用小程序版本特点低成本进入市场,达到流量的获取和转化. 伴随着资本的进入,小程序开发市场也因此越来 ...
- 安全测试6_Web安全工具第二节(代理抓包分析工具)
上节课讲了浏览器及扩展,这节课继续来学习下抓包分析. 首先看下下图,了解下代理工具的原理:代理就相当于收费站一样,任何要通过的车辆必须经过它. 浏览器的代理我们可以通过设置进行手动设置代理,或者通过P ...
- Kali渗透测试2-抓包/DNS工具
转载请注明出处. TCPDUMP:命令行网络抓包工具tcpdump -h tcpdump version 4.9.2 libpcap version 1.8.1 OpenSSL 1.1.0h 27 M ...
- CODING 代码资产安全系列之 —— 构建全链路安全能力,守护代码资产安全
本文作者:王振威 - CODING 研发总监 CODING 创始团队成员之一,多年系统软件开发经验,擅长 Linux,Golang,Java,Ruby,Docker 等技术领域.近两年来一直在 COD ...
- 基于 Istio 的全链路灰度方案探索和实践
作者|曾宇星(宇曾) 审核&校对:曾宇星(宇曾) 编辑&排版:雯燕 背景 微服务软件架构下,业务新功能上线前搭建完整的一套测试系统进行验证是相当费人费时的事,随着所拆分出微服务数量的不 ...
- 测试必备工具之最强抓包神器 Charles,你会了么?
前言 作为软件测试工程师,大家在工作中肯定经常会用到各种抓包工具来辅助测试,比如浏览器自带的抓包工具-F12,方便又快捷:比如时下特别流行的Fiddler工具,使用各种web和APP测试的各种场景 ...
- 高德全链路压测平台TestPG的架构与实践
导读 2018年十一当天,高德DAU突破一个亿,不断增长的日活带来喜悦的同时,也给支撑高德业务的技术人带来了挑战.如何保障系统的稳定性,如何保证系统能持续的为用户提供可靠的服务?是所有高德技术人面临的 ...
- <转>二十问全链路压测干货汇总(上)
本文转载自:微信公众号-数列科技<二十问全链路压测干货汇总(上)> 最近几年全链路压测无疑成为了一个热门话题,在各个技术峰会上都可以看到它的身影. 一些大型的互联网公司,比如阿里巴巴.京东 ...
- Molecule – 帮助你构建跨平台的 HTML5 游戏
Molecule 框架由拥有超过五年手机游戏开发经验的游戏开发者开发.由于移动浏览器与实际的 HTML5 规范的兼容性的改进和内部硬件的自然进化,HTML5 手机游戏真正有可能流行起来. 您可能感兴趣 ...
随机推荐
- datax从mysql迁移数据到OceanBase
datax部署 下载datax datax下载地址 安装datax tar -zxvf datax.tar.gz 使用datax 使用配置文件 { "job": { "s ...
- 用python做时间序列预测五:时间序列缺失值处理
有的时候,一些时刻或连续时间段内的值无法采集到,或者本身就没有值,本文将介绍如何处理这种情况. 一般而言,有以下几种方法: 对所有的缺失值用零填充. 前向填充:比如用周一的值填充缺失的周二的值 后向填 ...
- 丢掉WebView,使用JS+Rust开发跨端桌面应用-Deft
简介 随着Web技术的发展,越来越多的跨端应用选择了WebView作为基础解决方案.诚然WebView让跨端应用开发变得简单了很多,极大的提高了开发效率,但是,WebView也存在着一些广为诟病的缺点 ...
- 8-2 MySQL 索引的设计原则(超详细说明讲解)
8-2 MySQL 索引的设计原则(超详细说明讲解) @ 目录 8-2 MySQL 索引的设计原则(超详细说明讲解) 1. 测试数据准备 2. 哪些情况适合创建索引 2.1 字段的数值有唯一性的限制 ...
- 【Manim】空间与变换笔记
[Manim]空间与变换笔记 所有常量都可以在constants.py中找到 屏幕空间 屏幕中心为原点(0,0,0),遵循右手坐标系,向右为x轴正方向,向上为y轴正方向,向前为z轴负方向,旋转时正方向 ...
- 基于Openframeworks调取摄像头方式的定时抓拍保存图像方法小结
这次是采用Openframeworks来调取摄像头画面并抓图保存. 开始 借向导自动生成代码,因为要调取摄像头设备,因此增添ofVideoGrabber对象声明,又因为保存需求,所以还需添加ofPix ...
- ABC391D题解
前置知识: map priority_queue 思路 考虑预处理每一个图块在第几秒后会被删除. 如何预处理?我使用了一种非常暴力的做法,首先处理的过程肯定是从下往上的,于是每一个图块能被删除一定是它 ...
- 算子var_threshold
算子var_threshold 名称 var_threshold - 通过局部均值和标准差分析对图像进行阈值处理. 签名 var_threshold(Image : Region : MaskWidt ...
- PHP测试代码执行时间
https://blog.csdn.net/wyqwclsn/article/details/39930125 非常简单代码开始前加一个$start = microtime(true);代码结束后加一 ...
- 【配置化】C# dapper是怎么实现的?精短ORM
目录 一.什么是dapper 二.实现问题与思路 & 源码参考 三.小结 一.什么是dapper dapper是个组件,一个dll文件,可以通过NuGet下载. 作用:快速访问数据库并自动完成 ...