如何在不使用证书和手动代理配置的情况下拦截 Android 上的 HTTPS 流量
每个 Android 开发者都曾在某个时刻花费至少半天时间来配置网络调试器。场景总是一样:你想查看应用发送给后端的内容,结果却得到 SSLHandshakeException。
然后仪式开始了。首先,你生成一个自签名 CA 证书。然后尝试将其安装到测试设备的受信任证书存储中。从 Android 7.0(API 24)开始,系统默认忽略用户证书,所以你需要修改 network_security_config.xml,为 debug 构建配置 trust-anchors,然后重新构建 APK。如果你的项目配置了 SSL Pinning,或者你在 Android 14 上进行测试(系统证书处理变得更加严格),一个简单的响应头检查就会变成一个单独的工程任务。
Proxyman 团队的 atlantis-android 库从根本上解决了这个头疼的问题:它消除了配置代理和接触设备系统证书的需要。
Atlantis 的设计理念
像 Charles、Fiddler 或 Proxyman 本身这样的传统工具通常采用中间人(MitM)方案工作。设备将所有流量重定向到电脑的 IP 地址,桌面应用程序拦截请求,用自己的证书解密,然后转发它们。这正是证书信任问题和 Wi-Fi 代理配置变得棘手的原因。
Atlantis 的工作方式不同。它是一个紧凑的 Kotlin 库,作为网络客户端拦截器直接嵌入到应用的 debug 构建中。拦截器在应用已经组装好或刚刚解密请求和响应参数的时刻读取它们。然后库对这些数据进行序列化,通过 GZIP 压缩,并通过单独的本地 socket 直接传输到 macOS 上的 Proxyman 应用。
结果是,你获得了详细的网络活动日志,而无需干预 Android 设置,无需修改清单,也无需处理证书。
库的功能
Atlantis 覆盖了大多数日常网络调试任务:
- 直接从 OkHttp 拦截常规 HTTP 和 HTTPS 请求。
- 记录 WebSocket 事件:连接打开、发送消息、传入数据包和会话关闭。
- 完全兼容流行的网络客户端,包括 Retrofit 2.9+ 和 Apollo Kotlin 3.x/4.x。
- 通过 Network Service Discovery(mDNS)自动发现本地网络上运行的 Proxyman 实例。
如果你在官方 Android 模拟器上运行项目,库可以直接连接到主机,绕过网络发现。
如何集成到项目中
该库需要 Android API 26(Android 8.0)或更高版本、OkHttp 4.x 或 5.x 版本以及 Kotlin 1.9 或更高版本。
首先,将 JitPack 仓库添加到你的 settings.gradle.kts 文件中:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
之后,将依赖添加到你的应用的 build.gradle.kts 中。最好严格通过 debugImplementation 添加,以确保调试代码不会进入 release 构建:
dependencies {
debugImplementation("com.github.ProxymanApp:atlantis-android:v1.0.0")
}
该库也可以在 Maven Central 上获取,工件名称为 com.proxyman:atlantis-android:1.0.0。
快速开始
集成只需要几行代码。首先,在你的 Application 类中初始化 Atlantis:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Atlantis.start(this)
}
}
}
然后将拦截器添加到你的 OkHttpClient 配置中:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(Atlantis.getInterceptor())
.build()
如果你使用 Retrofit,将这个 okHttpClient 实例传递给 Retrofit.Builder(),所有请求就会自动出现在 Proxyman 窗口中。
处理 WebSocket
如果你的应用使用 WebSocket,标准的 OkHttp 拦截器就不够了,因为消息是在已打开的连接内传输的。对于这种情况,该库提供了一个特殊的监听器包装器:
val originalListener = object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
// обработка открытия
}
override fun onMessage(webSocket: WebSocket, text: String) {
// входящее сообщение
}
}
val wrappedListener = Atlantis.wrapWebSocketListener(originalListener)
okHttpClient.newWebSocket(request, wrappedListener)
现在你可以在桌面客户端中实时观察传入和传出的帧。
内部实现
该库的源代码简洁小巧,采用 Apache 2.0 许可证开源。仓库几乎没有重量级的第三方依赖。
架构由几个清晰的模块组成:
AtlantisInterceptor和AtlantisWebSocketListener在网络栈层面拦截数据。GzipCompression和Base64Utils打包请求体和二进制有效载荷,减少手机和电脑之间通信通道的负载。NsdServiceDiscovery通过 Android NSD API 负责在本地网络上发现_proxyman._tcp服务。Transporter打开到桌面应用程序的 TCP 连接并转发结构化数据包。
由于流量压缩,调试对应用性能的影响几乎可以忽略不计。
需要注意的局限性
在集成该库之前,有两件事需要考虑。
首先,Atlantis 与 Proxyman 桌面客户端绑定。如果你的团队习惯于专门使用 Wireshark 或 Charles,你将无法通过这个拦截器将数据转发到那里。
其次,该库只拦截你明确添加了拦截器的客户端的流量。如果应用中的第三方 SDK 通过自己的 HttpURLConnection 或 Cronet 发出网络调用,Atlantis 不会看到这些请求。要对第三方二进制文件进行完整分析,你仍然需要使用传统的 MitM 代理。
值得一试吗
如果你的主要开发机器运行 macOS,并且你已经使用 Proxyman 来调试 iOS 或后端,atlantis-android 可以节省大量时间。你将永远忘记在测试手机上设置 Wi-Fi 代理、重置证书和修改 network_security_config。只需构建一个 debug APK,在手机上打开应用,整个网络交换就会立即出现在你的屏幕上。
相关项目
