iOS H5 支付被“在小童园丁版中打开”提示劫持如何处理?
结论
这类问题通常不是 DNS 劫持,而是 iOS 的应用唤起规则发生了冲突。
支付宝 H5 支付会通过 URL Scheme 或 Universal Link 尝试唤起支付宝。如果“小童园丁版”误注册了相同的 URL Scheme,或支付跳转使用的域名与该应用建立了关联,iOS 就可能弹出“在‘小童园丁版’中打开此页面”。
排查时,先捕获弹窗出现前的完整跳转 URL,再按链接类型处理:
alipays://、alipay://等形式:排查 URL Scheme 冲突。https://...形式:排查 Universal Links、AASA 配置和页面中的应用唤起脚本。- 跳转到陌生域名:排查第三方脚本、广告 SDK、代理/CDN 配置和网络环境。
修改 DNS、清理浏览器缓存或调整支付回调地址,一般解决不了应用关联冲突。
先确认是哪一种跳转
不要只记录支付入口地址。从“选择支付宝”开始,到系统弹窗出现前为止,每一次跳转都需要记录,包括:
- 当前页面 URL
- HTTP 301、302、303、307、308 响应中的
Location - 页面内 JavaScript 设置的
location.href <iframe>加载的地址- 最终触发应用唤起的 URL
- 出现问题的 iOS 版本、浏览器类型和应用版本
- 是否安装支付宝,以及只安装“小童园丁版”时是否仍会出现
可以按以下步骤排查:
- 使用 macOS Safari 的“开发”菜单连接出现问题的 iPhone。
- 打开对应网页的 Web Inspector。
- 在 Network 中勾选保留请求记录。
- 从支付入口重新操作,记录重定向链和 Console 输出。
- 分别测试安装和卸载“小童园丁版”后的行为。
如果支付页面运行在自有 App 的 WKWebView 中,也可以临时记录导航请求:
import WebKit
final class PaymentNavigationLogger: NSObject, WKNavigationDelegate {
func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
) {
if let url = navigationAction.request.url {
print("Payment navigation:", url.absoluteString)
}
decisionHandler(.allow)
}
}
日志中可能包含订单号、用户标识或签名参数。收集后应先脱敏,不要直接上传到公开平台。
情况一:URL Scheme 被其他应用注册
如果弹窗前的地址类似:
alipays://...
或者是其他非 HTTP Scheme:
some-scheme://...
很可能有多个 App 注册了同一个 Scheme。
iOS 不要求 URL Scheme 全局唯一。多个应用都可以在 Info.plist 中声明相同的 CFBundleURLSchemes。发生冲突后,网页无法指定某个 Bundle ID 必须处理该链接,商户页面也不能通过 JavaScript 强制选择支付宝。
问题应用中可能存在类似配置:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>example.payment</string>
<key>CFBundleURLSchemes</key>
<array>
<string>alipays</string>
</array>
</dict>
</array>
这段配置只用于说明位置,并不代表支付宝当前使用的全部 Scheme。实际排查应以现场捕获的 URL 和支付宝当前接入文档为准。
处理方式
确认存在 Scheme 冲突后:
- 检查商户侧是否自行拼接了支付宝 Scheme。
- 删除非官方中转页或来源不明的“自动拉起支付宝”脚本。
- 使用支付宝官方 H5 支付接口返回的表单或跳转地址,不要自行替换协议头。
- 联系“小童园丁版”的开发方,并提供触发 URL、录屏和复现步骤。
- 由该 App 的开发方删除误注册的支付宝 Scheme,重新发布版本。
要彻底解决 Scheme 冲突,通常需要冲突 App 修改配置。网页无法撤销其他已安装应用注册的 Scheme,也无法可靠控制最终由哪个应用处理。
情况二:Universal Link 关联异常
如果弹窗前仍是 HTTPS 地址,例如:
https://pay.example.com/path
需要确认该域名是否通过 Universal Links 关联到了“小童园丁版”。
iOS 会读取域名下的 AASA 文件:
https://example.com/.well-known/apple-app-site-association
典型结构如下:
{
"applinks": {
"details": [
{
"appIDs": [
"TEAM_ID.com.example.app"
],
"components": [
{
"/": "/payment/*"
}
]
}
]
}
}
App 的签名权限中也会声明关联域名:
applinks:example.com
需要逐项核对:
- 弹窗前的 HTTPS 域名是否属于自己。
- AASA 中是否包含“小童园丁版”的 App ID。
- CDN、对象存储或反向代理是否返回了错误的 AASA 文件。
- AASA 是否存在缓存、跨环境复用或域名指向错误。
- 测试环境和正式环境是否共用了关联域名。
- 第三方支付中转域名是否确实由对应支付服务商控制。
可以检查响应头和文件内容:
curl -i https://example.com/.well-known/apple-app-site-association
AASA 应直接返回有效 JSON,不能跳转到登录页、HTML 错误页或其他域名。具体的响应要求以当前 Apple 文档为准。
如果域名属于商户,应修正 AASA、CDN 和 App 的 Associated Domains 配置。如果域名属于支付服务商,不要自行修改或代理其 AASA。应将完整 URL、发生时间和复现环境提交给服务商核查。
情况三:页面脚本或第三方组件触发了错误链接
如果最终 URL 既不是支付宝的官方跳转,也不是预期的 Universal Link,需要检查页面中是否存在以下内容:
- 来历不明的支付封装脚本
- 广告、统计或客服脚本
- URL 短链和第三方中转服务
- 根据 User-Agent 执行的应用唤起逻辑
- 隐藏的
<iframe> - 动态下发的 JavaScript
- 被篡改的 CDN 静态资源
- 通过
window.location或模拟点击触发的跳转
可以在测试环境中为重要跳转临时增加日志:
function navigateToPayment(url) {
const parsed = new URL(url, window.location.href);
console.info("payment navigation", {
protocol: parsed.protocol,
host: parsed.host,
pathname: parsed.pathname
});
window.location.assign(parsed.href);
}
前端日志中不要输出支付签名、授权码、会话令牌或完整查询参数。
还要检查页面响应是否符合预期:
curl -I "https://merchant.example.com/payment/entry"
如果异常只出现在特定 Wi-Fi 或运营商网络下,再对比不同网络的 DNS 解析结果、TLS 证书和响应内容。只有发现域名解析到异常地址、证书不匹配或页面内容被替换等证据,才需要沿着 DNS 污染、中间人代理或网络劫持的方向继续调查。
建议的定位顺序
可以按以下顺序缩小范围:
- 卸载“小童园丁版”后重新支付。
- 保持其他条件不变,安装该 App 后再次测试。
- 捕获系统弹窗前的最终 URL。
- 根据 URL 判断是 Scheme 还是 HTTPS Universal Link。
- 分别在 Safari、微信内置浏览器和自有
WKWebView中测试。 - 切换 Wi-Fi 和蜂窝网络,排除网络变量。
- 移除支付页中非必要的第三方脚本后复测。
- 使用支付宝返回的原始支付响应建立最小复现页面。
如果最小页面仍能稳定复现,通常可以排除业务页面逻辑。此时应将问题提交给支付宝和冲突 App 的开发方处理。
提交问题时应提供的信息
为减少问题在多方之间反复转交,建议一次准备好以下材料:
- 问题录屏
- 弹窗前的完整 URL,敏感参数需脱敏
- HTTP 重定向链
- iOS 版本和设备型号
- 使用的是 Safari、内置浏览器还是
WKWebView - 支付宝版本
- “小童园丁版”版本
- 安装和卸载该 App 后的对照结果
- 不同网络环境下的对照结果
- 最小复现页面
- 问题发生时间及对应的商户订单号
注意事项
不要反复尝试不同的私有 Scheme 来绕过问题,也不要根据“先安装的 App”或安装顺序判断哪个应用会被唤起,这些方式都不可靠。
如果确认其他 App 抢注了支付宝 Scheme,商户侧最多只能提供降级入口和用户提示,无法从网页端彻底修复。需要由冲突 App 移除错误注册,或由支付服务商提供不依赖冲突 Scheme 的官方唤起路径。
不要把支付地址放入未经验证的短链、跳转平台或第三方“防封装”服务。这些服务会增加重定向层级,让 URL Scheme、Universal Links 和安全问题更难排查。
备注:内容仅供参考。
