17、深层链接与URL Scheme:验证绕过、参数污染、钓鱼攻击

深层链接(Deep Link)和 URL Scheme,说白了就是 App 的「任意门」。

你点一个链接,系统直接拉起某个 App,甚至跳转到某个具体页面。这功能确实方便,但也是攻击者的最爱。我做过不少 App 的渗透测试,深层链接这块几乎是「重灾区」。今天我们就来聊聊,这些「任意门」到底藏着哪些坑。

17.1 深层链接的基本原理

先搞清楚它怎么工作的。

Android 里,App 通过 intent-filter 声明自己能处理哪些 URL。比如:

<activity android:name=".LoginActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="myapp"
            android:host="login" />
    </intent-filter>
</activity>

这样,用户点击 myapp://login 时,系统就会直接打开 LoginActivity

嗯,听起来很完美。但问题来了——你信任这个链接里的参数吗?

17.2 验证绕过:谁在敲门?

我见过最典型的漏洞,就是深层链接不校验来源。

很多 App 在 onNewIntent()onCreate() 里直接拿 URL 参数,然后执行敏感操作。比如重置密码、修改绑定手机号。

典型案例:

某金融 App 的深层链接 mybank://resetPassword?token=xxx,直接跳转到密码重置页。攻击者只要伪造一个链接,诱导用户点击,就能重置密码。

为什么会这样?因为 App 没有验证这个链接是从哪里来的。它可能是从短信、浏览器、甚至恶意 App 里发出来的。

我建议的做法:

  • 对敏感操作,必须校验 referrer 或来源包名
  • 使用 getCallingPackage() 检查调用者
  • 关键参数必须签名或加密,不能明文传输

避坑指南:

我曾经遇到一个 App,它只校验了 Scheme 和 Host,但没校验 Path。攻击者用 myapp://login 就能绕过,实际上应该用 myapp://resetPassword 才能触发重置。所以,路径校验也要做完整。

17.3 参数污染:你看到的不是真的

参数污染,说白了就是攻击者在 URL 里塞入额外参数,覆盖掉原有的逻辑。

举个例子:

// 正常链接
myapp://pay?amount=100&to=userA

// 攻击者构造的链接
myapp://pay?amount=100&to=userA&amount=1

如果服务端或客户端解析参数时,取了最后一个 amount 值,那用户就只付了 1 块钱。或者更糟,取了第一个值,但后续逻辑被覆盖。

我见过一个电商 App,它的深层链接里有个 redirect 参数,用于支付成功后跳转。攻击者把 redirect 改成钓鱼页面,用户支付完就被带到假网站。

怎么防?

  • 服务端和客户端统一使用标准 URI 解析库,不要自己写 split
  • 对参数做白名单校验,只允许预期的 key
  • 敏感参数(如金额、用户ID)必须签名,防止篡改

注意:

参数污染不仅限于 URL 参数。Intent 的 extra 数据也可能被污染。如果 App 从 Intent 里取数据,一定要做类型检查和边界校验。

17.4 钓鱼攻击:披着羊皮的狼

深层链接钓鱼,是攻击者最常用的手法之一。

攻击者可以注册一个类似的 URL Scheme,比如 myappmyappp(多一个 p)。用户一不小心点了恶意链接,就被拉到了假 App 或假页面。

更高级的玩法是「Scheme 劫持」。如果系统里有多个 App 注册了同一个 Scheme,系统会弹出选择框。攻击者可以提前注册一个恶意 App,诱导用户选择它。

我遇到过的真实案例:

  • 某社交 App 的 share 链接,被恶意 App 劫持,用户点击后直接跳转到广告页面
  • 某银行 App 的 login 链接,被钓鱼 App 模仿,用户输入了账号密码

防御措施:

  • 使用 Android App Links(HTTP 链接 + 数字证书验证),这是最安全的方案
  • 如果必须用自定义 Scheme,建议加上 android:hostandroid:pathPrefix 限制
  • 在 App 内部,对敏感页面增加二次确认(比如输入密码或指纹)

个人经验:

我建议所有涉及资金、隐私的深层链接,都走 HTTPS 的 App Links。虽然配置起来麻烦点,但安全性高很多。自定义 Scheme 说白了就是个「野路子」,能不用就别用。

17.5 自动化扫描与手动测试

讲完漏洞,我们聊聊怎么测。

自动化扫描:

  • 使用 drozer 扫描所有暴露的 Activity,看哪些有 intent-filter
  • adb 模拟发送深层链接:adb shell am start -W -a android.intent.action.VIEW -d "myapp://login"
  • 使用 MobSF 静态分析,检查 URL 参数是否被硬编码或未校验

手动测试重点:

  • 遍历所有深层链接,尝试修改参数值(如 token、uid、amount)
  • 测试参数污染:在 URL 末尾追加同名参数
  • 测试 Scheme 劫持:安装一个恶意 App,注册相同 Scheme,看系统行为
  • 检查 onNewIntent()onCreate() 中的 Intent 处理逻辑

核心思路:

深层链接的本质是「外部输入」。任何外部输入都不可信。你想想看,一个链接从浏览器、短信、二维码里来,中间经过了多少环节?每个环节都可能被篡改。

17.6 知识体系图

下面这张图,帮你理清深层链接安全的整体脉络:

深层链接安全 验证绕过 参数污染 钓鱼攻击 未校验来源 路径校验缺失 同名参数覆盖 重定向劫持 Scheme 劫持 仿冒 Scheme 防御措施:App Links + 参数签名 + 来源校验 测试:drozer / adb / MobSF / 手动Fuzzing

17.7 总结

深层链接是个好东西,但用不好就是灾难。

我个人习惯是:能用 App Links 就用 App Links,实在不行再考虑自定义 Scheme。而且,所有从 URL 里拿到的参数,都要当成「用户输入」来处理——校验、签名、过滤,一步都不能少。

你想想看,一个链接能拉起你的 App,甚至能直接触发支付、修改密码、读取隐私。这权限太大了,必须管好。

最后提醒一句:

不要相信任何来自外部 Intent 的数据。哪怕它看起来像是你自己 App 发出来的。攻击者可以伪造一切。


公众号:蓝海资料掘金营,微信deep3321