百趣云 百趣云的博客

App 内嵌 H5 的 JSBridge 协议分析:混合开发的信息命脉

JSBridge 是混合开发 App 的"海关"

混合开发 App(原生壳 + H5 核心页面)里,所有 native 能力和 H5 逻辑的交互都走 JSBridge:H5 调 native 算签名、native 给 H5 推登录态、H5 调 native 起支付……把 JSBridge 看光,混合 App 就没有秘密

JSBridge 有两种主流实现,分析前先分清对手用哪种。

实现一:addJavascriptInterface(直接调用型)

native 把 Java 对象暴露给 JS:

webView.addJavascriptInterface(new BridgeObject(), "NativeBridge");

class BridgeObject {
    @JavascriptInterface
    public String getSign(String data) {   // H5 里 window.NativeBridge.getSign(data) 直接调
        return SignUtils.md5(data + SALT);
    }
}

H5 侧调用是同步的:window.NativeBridge.getSign("xxx") 直接拿到返回值。

分析方法:Frida hook addJavascriptInterface 拿 bridge 名和类名,然后 hook 这个类的所有 @JavascriptInterface 方法,输入输出全透明(前文 WebView 监控篇有完整脚本)。

实现二:URL 拦截型(伪协议)

H5 通过跳转伪协议 URL 发消息,native 在 WebViewClient 里拦截:

// H5 侧
location.href = 'jsbridge://getSign?data=xxx&callback=cb_123';
// 或 iframe.src = ...(解决 location 跳转的副作用)
// native 侧
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith("jsbridge://")) {
        handleBridge(url);   // 解析方法名和参数
        return true;         // 拦截,不真正跳转
    }
    return super.shouldOverrideUrlLoading(view, url);
}

返回值通过 evaluateJavascript("cb_123(result)") 回调给 H5——异步的

分析方法:hook shouldOverrideUrlLoading 看 H5→native 方向,hook evaluateJavascript/loadUrl("javascript:...") 看 native→H5 回调方向。

精髓一:协议格式逆向

URL 拦截型的 bridge URL 就是一套私有协议,把它当协议文档来逆:

jsbridge://module/action?param1=v1&param2=v2&callback=cb_xxx

收集一批真实调用,整理出方法清单:

URL 模式功能参数回调数据
jsbridge://security/getSign签名data, timestampsign 字符串
jsbridge://device/getInfo设备信息json
jsbridge://pay/start支付orderId, amount支付结果码

这张表就是混合 App 的"API 文档",比逆 Java 代码快得多。

精髓二:签名逻辑的"借鸡生蛋"

发现签名走 bridge(H5 调 native 算签名)后,最优雅的利用方式不是逆算法,而是注入 JS 直接调

// Frida 里拿到 WebView 实例,注入 JS 调用 bridge
Java.perform(function() {
    Java.choose('android.webkit.WebView', {
        onMatch: function(wv) {
            wv.evaluateJavascript(
                "window.NativeBridge.getSign('test_data')",
                null
            );
        },
        onComplete: function() {}
    });
});

对 URL 拦截型,注入 location.href='jsbridge://...' 并 hook 回调函数拿结果。配合 HTTP 服务包装,就是一个"签名即服务"——H5 的签名逻辑原封不动为你所用。

精髓三:bridge 的安全问题即逆向入口

很多 bridge 实现有安全缺陷,这些缺陷恰恰是逆向的捷径:

  1. 方法未鉴权:bridge 方法对任何加载的 H5 可用——你可以让自己的页面调它的签名方法
  2. 参数未校验jsbridge://file/read?path=/data/data/... 这类文件操作 bridge 可能能读私有目录(cookie、token 文件)
  3. 回调注入:callback 名拼接进 JS 执行,构造特殊 callback 名可注入任意 JS

审计 bridge 时把这些当 checklist,经常有意外的洞。

总结

  1. 分清两种实现:addJavascriptInterface(同步直调)vs URL 拦截(异步回调)
  2. 前者 hook 方法,后者 hook shouldOverrideUrlLoading + evaluateJavascript
  3. bridge 调用清单就是混合 App 的 API 文档
  4. 签名走 bridge 时,注入 JS 直调比逆算法优雅得多

交流微信:run1255

By 百趣云 阅读量:2 On