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,比如 myapp 和 myappp(多一个 p)。用户一不小心点了恶意链接,就被拉到了假 App 或假页面。
更高级的玩法是「Scheme 劫持」。如果系统里有多个 App 注册了同一个 Scheme,系统会弹出选择框。攻击者可以提前注册一个恶意 App,诱导用户选择它。
我遇到过的真实案例:
- 某社交 App 的
share链接,被恶意 App 劫持,用户点击后直接跳转到广告页面 - 某银行 App 的
login链接,被钓鱼 App 模仿,用户输入了账号密码
防御措施:
- 使用 Android App Links(HTTP 链接 + 数字证书验证),这是最安全的方案
- 如果必须用自定义 Scheme,建议加上
android:host和android: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 知识体系图
下面这张图,帮你理清深层链接安全的整体脉络:
17.7 总结
深层链接是个好东西,但用不好就是灾难。
我个人习惯是:能用 App Links 就用 App Links,实在不行再考虑自定义 Scheme。而且,所有从 URL 里拿到的参数,都要当成「用户输入」来处理——校验、签名、过滤,一步都不能少。
你想想看,一个链接能拉起你的 App,甚至能直接触发支付、修改密码、读取隐私。这权限太大了,必须管好。
最后提醒一句:
不要相信任何来自外部 Intent 的数据。哪怕它看起来像是你自己 App 发出来的。攻击者可以伪造一切。
公众号:蓝海资料掘金营,微信deep3321