mtgsig：把签名元信息摆在明面上的设计美团 H5 接口的请求头里有一个 mtgsig，值是一串编码后的 json。解码后字段含义几乎写在脸上：{ "a1": "1.1", // 算法版本 "a2": 1787968800000, // 毫秒时间戳 "a3": "f3d4...", // 随机数/nonce "a4": "dfp值", // 设备指纹 "a5": "GET", // 请求方法 "a6": "/api/xxx", // 请求路径 "a7": "query摘要", "a8": "body摘要", "a9": "最终签名" }字段编号是语义化的：a5、a6 告诉你签名覆盖了方法和路径，a7、a8 告诉你 query 和 body 都参与了摘要。这种"元信息透明"的设计让服务端校验策略可以灵活升级，也给逆向者画了张地图。定位：签名是异步的美团 H5 的签名 SDK 是独立加载的 mtgsig 相关 chunk。定位时注意一个特点：签名函数返回 Promise——因为它要先异步采集设备指纹（a4 字段的 dfp 值），再算签名。所以 hook 点要选在异步完成之后：const _open = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { this._method = method; this._url = url; return _open.apply(this, arguments); }; const _setH = XMLHttpRequest.prototype.setRequestHeader; XMLHttpRequest.prototype.setRequestHeader = function(k, v) { if (k.toLowerCase() === 'mtgsig') { console.log('mtgsig for', this._method, this._url); debugger; // 断下后看调用栈，Promise then 链的上一环就是签名函数 } return _setH.apply(this, arguments); };算法拆解跟进签名主函数后，流程很标准：采集 dfp：设备指纹（ua、canvas、屏幕、字体等），独立模块异步生成，结果有缓存拼接待签串：method + path + 排序后的 query + body 的 SHA256 + 时间戳 + nonce + dfp，按固定模板拼接HMAC-SHA256：密钥来自混淆字符串池，按接口分组多组 key组装输出：签名连同 a1-a8 元信息一起编码成 mtgsig 头密钥的抠取技巧：美团前端把密钥做了字符串加密存储，运行时通过解密函数还原。别去静态分析解密算法——直接在密钥使用点下断点（HMAC 的 key 参数），内存里拿到的就是明文，抄下来即可。工程实现import hashlib, hmac, json, time, random, string def make_mtgsig(method, path, query, body, dfp, key): ts = int(time.time() * 1000) nonce = ''.join(random.choices(string.hexdigits.lower(), k=16)) body_hash = hashlib.sha256(body.encode()).hexdigest() if body else '' # 待签串模板以实际版本为准，结构示意： raw = "&".join([method.upper(), path, query, body_hash, str(ts), nonce, dfp]) sign = hmac.new(key.encode(), raw.encode(), hashlib.sha256).hexdigest() return {"a1": "1.1", "a2": ts, "a3": nonce, "a4": dfp, "a5": method.upper(), "a6": path, "a7": query, "a8": body_hash, "a9": sign}精髓：四个实战要点dfp 是独立 SDK，可以固定。dfp 采集一次后有缓存机制，协议模拟时从真实浏览器采一个固定使用。但注意 dfp 和 ua 的匹配关系，换 ua 必须换 dfp。时间戳容忍窗口约 5 分钟。a2 和服务器时钟偏差超窗直接返回 mtgsig expired。走代理链路时注意延迟，必要时本机校时。App 端是另一套（MTGuard）。美团 App 用的是 com.meituan.android.common.mtguard 的 native 方案，和 H5 的 mtgsig 不通用。接 App 协议要走 Frida hook MTGuard 的路线，别拿 H5 的成果硬套。签名错误无明确报错。mtgsig 校验失败常表现为返回空数据或跳转验证页，调试时用"我的"这类简单登录态接口做签名正确性基准。总结mtgsig 解码后是"签名+元信息"的透明结构，字段本身就是逆向地图签名是异步的（先采指纹），hook 点要选在 Promise 完成之后密钥在使用点内存里拿明文，别静态分析字符串解密H5 的 mtgsig 和 App 的 MTGuard 是两套体系，别混用