Android 深层链接、Intent 和 WebView 桥接评估辅助工具
apk-interceptor 是一个专为授权应用安全评估而设计的便携式 Android 测试 APK。它帮助安全工程师验证 Android 应用如何处理外部入口点,例如自定义 URI 方案、深层链接、导出的 Activity 和 WebView JavaScript 桥接。
该工具有意受限:
android.permission.INTERNETcontent:// 载荷文件在 Android 应用安全评估过程中,静态分析得出的许多发现仍需要在设备上制作一个小型概念验证后才能确认:注册一个自定义 URI 方案、发送一个显式 Intent、提供一个本地 content:// 载荷,或者检查 JavaScript 是否能访问 WebView 桥接。
为每种情况构建一个新的临时测试应用既重复又容易出错。清单条目、权限标识符、URI 授权、包名或 Intent 构造上的微小差异都会拖慢验证速度,并使结果更难复现。
apk-interceptor 的创建就是为了使确认步骤可重复。你不必为每次评估编写一个新的 PoC APK,而是使用所需的授权方案或应用 ID 构建此工具,在设备上运行测试,并通过设计保持工作流程受限:无 INTERNET 权限,无外部数据传输,无 Shell 执行,无 root 依赖。
apk-interceptor 可用于以下评估任务:
| 场景 | 模块 | 它有助于验证的内容 |
|---|---|---|
| 自定义 URI 方案劫持 | 拦截器 | 另一个应用是否可以注册相同的自定义方案并接收链接 |
| 深层链接参数处理 | 发送器 | 被评估应用是否接受不安全的查询/路径参数 |
| 导出 Activity 暴露 | 发送器 | 导出的 Activity 是否可以被其他应用直接启动 |
通过 content:// 暴露 WebView 桥接 | 载荷 + 发送器 | 本地 HTML 载荷是否可以访问 WebView JavaScript 桥接 |
| 本地载荷语法检查 | 载荷 | 你的 HTML/JS 载荷是否在自测 WebView 中运行 |
详细的漏洞演练:
该应用会为发送的 Intent、接收的深层链接、桥接回调、JavaScript 结果和错误维护一个内存评估日志。当应用进程被杀死时,日志会消失。由于日志不会持久化,请在工作时通过截图或屏幕录制来捕获证据。
apk-interceptor 是一个确认工具,而不是发现或利用框架。它假设你已经通过静态分析知道要测试什么(方案、Activity 类、桥接名称),并为你提供一种安全、在设备上的方式来验证可达性并捕获证据。它设计为可安装在评估设备上,甚至可以与客户共享,因此它不包含 INTERNET 权限、Shell 执行、数据泄露或 root 要求。
它与常见 Android 工具集的定位对比:
apk-interceptor 相比其他方案具有最明显优势的两个领域:
adb/静态分析无法展示的。content:// → WebView 桥接验证:一个非导出的单文件提供程序,其载荷仅通过临时 Intent 读取授权传递,外加一个本地自测 WebView,用于先验证载荷语法。apk-interceptor 对发送和拦截的处理不同,这是使用前需要理解的最重要的一点:
| 操作 | 模块 | 构建时是否需要自定义方案? |
|---|---|---|
| 发送 Intent 或深层链接到另一个应用 | 发送器 | 否,运行时输入任意 URI、包名或 Activity |
| 拦截(接收)自定义方案的深层链接 | 拦截器 | 是,方案在构建时固定到 APK 中 |
要发送一个精心构造的深层链接到被评估应用,你不需要重新构建:使用发送器标签页的隐式深层链接模式并输入任意 URI。
要拦截一个深层链接,即让 Android 将自定义方案路由到 apk-interceptor,以便你可以观察可能的方案劫持,你必须通过 --scheme 使用该方案构建 APK。方案在构建时被有意固定(一个设计护栏);apk-interceptor 永远不会在运行时注册任意方案。如果你更改了正在评估的方案,请重新构建并重新安装。
adb使用你被授权评估的自定义 URI 方案构建 APK:
./build-interceptor.sh --scheme <authorized_custom_scheme>
adb install ./out/apk-interceptor-<authorized_custom_scheme>-debug.apk
可选的构建标志:
./build-interceptor.sh \
--scheme <authorized_custom_scheme> \
--app-id <custom.application.id> \
--output ./out
--app-id 在构建时设置安装的应用 ID(设备上的包标识和 content://<applicationId>.payload 授权)。默认值为 com.sterrasec.apkinterceptor。当你需要为不同评估创建多个可单独安装的构建时,使用 --app-id 覆盖。Windows 等效项是 build-interceptor.bat。
默认方案 intercept-poc-example 是一个无害的占位符。构建脚本拒绝使用该默认方案生成评估 APK。
在首次启动每个应用版本时,apk-interceptor 会显示一个授权使用对话框。在你点击我理解后,同一版本将不再显示该对话框。 发送器标签页仍然会显示一个持久警告,因为它可以向其他应用发送 Intent。
| 发送器 | 载荷 | 拦截器 |
|---|---|---|
![]() | ![]() | ![]() |
使用此标签页验证自定义 URI 方案的拦截。
它显示的内容:
基本工作流程:
关于发送测试深层链接:它总是发送 <scheme>://test?<your params>,使用固定的 test 主机,因此它旨在确认 apk-interceptor 接收并记录该方案,而不是驱动被评估应用的特定深层链接路由。要发送与被评估应用所需主机或路径匹配的精心构造的深层链接,请改用发送器标签页的隐式深层链接模式。
adb 示例:
adb shell am start -W \
-a android.intent.action.VIEW \
-d 'my-authorized-scheme://test?source=adb\&message=hello%20world'
当通过 adb shell 发送多个查询参数时,请使用 \&;否则设备 shell 可能会将 & 视为命令分隔符。
预期结果:
RECEIVED 日志条目使用此标签页在授权测试期间发送受控的 Intent。
模式:
Intent(ACTION_VIEW, Uri.parse(uri))字段和控制:
隐式深层链接工作流程:
显式 Activity 工作流程:
说明:
content:// 附件很有用。data 传递,这会覆盖你在隐式深层链接模式下输入的 URI,因此该选项在那里被隐藏。PayloadProvider 未导出。被评估应用只能通过 Intent 中的 FLAG_GRANT_READ_URI_PERMISSION 授予临时读取权限来读取附加的 content:// 载荷。保持该标志启用,并通过 Intent 传递 URI。以任何其他方式打开的 content:// URI 将无法被其他应用读取。使用此标签页创建本地 HTML 载荷,并在 apk-interceptor 自己的自测 WebView 中验证 JavaScript 桥接语法。
它包含的内容:
content:// URI生成的载荷 URI 格式:
content://<applicationId>.payload/current.html
提供程序只提供这个固定文件:
filesDir/payloads/current.html
载荷自测工作流程:
localBridge。BRIDGE_RESULT、console.log 和 evaluateJavascript result 条目。示例自测 JavaScript:
console.log("payload loaded");
window.localBridge.logResult(window.localBridge.getInfo());
自测桥接暴露了:
window.<bridgeName>.logResult("message");
window.<bridgeName>.getInfo();
重要限制:
自测 WebView 确认你的本地载荷和桥接调用语法在 apk-interceptor 内部工作。它无法观察另一个应用的 WebView 是否执行了你的载荷或调用了它自己的桥接。对于被评估的应用,请通过该应用的 UI、日志、测试钩子或 Chrome DevTools(如果应用可调试)进行验证。
风险:
一个 Android 应用注册了一个自定义 URI 方案,而不是经过验证的应用链接。任何其他应用都可以注册相同的方案,因此 Android 可能会显示应用选择器或将链接路由到不同的应用。
使用 apk-interceptor 检查:
步骤:
要捕获的证据:
风险:
被评估应用信任深层链接参数用于导航、URL 加载、功能标志、账户选择或渲染,而没有充分的验证。
使用 apk-interceptor 检查:
步骤:
示例占位符:
my-authorized-scheme://open?next=https%3A%2F%2Fauthorized-test.example%2Flanding
不要使用真实的第三方域或账户,除非它们明确在范围内。
风险:
导出的 Activity 执行敏感操作或显示敏感数据,而不验证调用者、用户状态或所需的授权。
使用 apk-interceptor 检查:
步骤:
content:// 载荷 URI。要捕获的证据:
content:// 暴露 WebView JavaScript 桥接风险:
被评估应用将不可信的 content:// Intent 数据加载到一个也通过 addJavascriptInterface 暴露 JavaScript 桥接的 WebView 中。
使用 apk-interceptor 检查:
content:// 传递步骤:
重要限制:
除非另一个应用显式返回或显示结果,否则 apk-interceptor 无法接收来自它的结果。该工具设计用于传递本地载荷并验证语法,而不是窃取数据。
验证 APK 不请求网络访问:
aapt dump permissions ./out/apk-interceptor-<scheme>-debug.apk
预期输出:没有 android.permission.INTERNET。
显式触发一个深层链接到 apk-interceptor:
adb shell am start -W \
-n com.sterrasec.apkinterceptor/.InterceptActivity \
-a android.intent.action.VIEW \
-d 'my-authorized-scheme://test?source=adb'
通过 Android 的解析器触发一个深层链接:
adb shell am start -W \
-a android.intent.action.VIEW \
-d 'my-authorized-scheme://test?source=adb'
显式命令确认 InterceptActivity 的行为。隐式命令确认清单 intent-filter 和解析器的行为。
单元测试使用 Robolectric 在 JVM 上运行,因此不需要设备或模拟器。它们覆盖 PayloadProvider,包括路径白名单和遍历检查,确保提供程序只提供单个 current.html 载荷。
./gradlew testDebugUnitTest
测试结果写入 app/build/reports/tests/testDebugUnitTest/index.html。相同的任务在每次推送到 main 和拉取请求时在 CI 中运行。
android.permission.INTERNET/current.html 由 PayloadProvider 提供MIT
| 工具 | 角色 | apk-interceptor 的不同之处 |
|---|
| jadx / MobSF / QARK / Semgrep | 查找易受攻击的入口点(静态) | apk-interceptor 不扫描或反编译;它确认你已经发现的发现 |
deep-C / NSdeepLink / adb am start | 枚举并发送深层链接 | apk-interceptor 也能发送,但其区别在于接收被劫持的方案并显示确切的 URI 和参数 |
| drozer | 通用设备端攻击框架(代理 + 通常 root) | apk-interceptor 是一个轻量级单 APK,具有有意的安全护栏,范围更窄,更易于客户端安全分发 |
| Metasploit / Frida | 武器化或挂钩(例如 addJavascriptInterface RCE) | apk-interceptor 仅检查桥接的可达性,使用无害载荷;它从不窃取数据或执行 Shell 命令 |