PAYATHON 2026

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 版本、浏览器类型和应用版本
  • 是否安装支付宝,以及只安装“小童园丁版”时是否仍会出现

可以按以下步骤排查:

  1. 使用 macOS Safari 的“开发”菜单连接出现问题的 iPhone。
  2. 打开对应网页的 Web Inspector。
  3. 在 Network 中勾选保留请求记录。
  4. 从支付入口重新操作,记录重定向链和 Console 输出。
  5. 分别测试安装和卸载“小童园丁版”后的行为。

如果支付页面运行在自有 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 冲突后:

  1. 检查商户侧是否自行拼接了支付宝 Scheme。
  2. 删除非官方中转页或来源不明的“自动拉起支付宝”脚本。
  3. 使用支付宝官方 H5 支付接口返回的表单或跳转地址,不要自行替换协议头。
  4. 联系“小童园丁版”的开发方,并提供触发 URL、录屏和复现步骤。
  5. 由该 App 的开发方删除误注册的支付宝 Scheme,重新发布版本。

要彻底解决 Scheme 冲突,通常需要冲突 App 修改配置。网页无法撤销其他已安装应用注册的 Scheme,也无法可靠控制最终由哪个应用处理。

如果弹窗前仍是 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 污染、中间人代理或网络劫持的方向继续调查。

建议的定位顺序

可以按以下顺序缩小范围:

  1. 卸载“小童园丁版”后重新支付。
  2. 保持其他条件不变,安装该 App 后再次测试。
  3. 捕获系统弹窗前的最终 URL。
  4. 根据 URL 判断是 Scheme 还是 HTTPS Universal Link。
  5. 分别在 Safari、微信内置浏览器和自有 WKWebView 中测试。
  6. 切换 Wi-Fi 和蜂窝网络,排除网络变量。
  7. 移除支付页中非必要的第三方脚本后复测。
  8. 使用支付宝返回的原始支付响应建立最小复现页面。

如果最小页面仍能稳定复现,通常可以排除业务页面逻辑。此时应将问题提交给支付宝和冲突 App 的开发方处理。

提交问题时应提供的信息

为减少问题在多方之间反复转交,建议一次准备好以下材料:

  • 问题录屏
  • 弹窗前的完整 URL,敏感参数需脱敏
  • HTTP 重定向链
  • iOS 版本和设备型号
  • 使用的是 Safari、内置浏览器还是 WKWebView
  • 支付宝版本
  • “小童园丁版”版本
  • 安装和卸载该 App 后的对照结果
  • 不同网络环境下的对照结果
  • 最小复现页面
  • 问题发生时间及对应的商户订单号

注意事项

不要反复尝试不同的私有 Scheme 来绕过问题,也不要根据“先安装的 App”或安装顺序判断哪个应用会被唤起,这些方式都不可靠。

如果确认其他 App 抢注了支付宝 Scheme,商户侧最多只能提供降级入口和用户提示,无法从网页端彻底修复。需要由冲突 App 移除错误注册,或由支付服务商提供不依赖冲突 Scheme 的官方唤起路径。

不要把支付地址放入未经验证的短链、跳转平台或第三方“防封装”服务。这些服务会增加重定向层级,让 URL Scheme、Universal Links 和安全问题更难排查。

备注:内容仅供参考。