百趣云 百趣云的博客

淘宝 h5 mtop 签名:_m_h5_tk 体系详解

mtop 签名:阿里系的"祖传配方"

淘宝 H5 的 mtop 接口签名是阿里系应用最广的一套方案,公式一句话说完:

sign = md5(token + "&" + t + "&" + appKey + "&" + data)
  • token:cookie _m_h5_tk 的下划线前段(_m_h5_tk=abc123_def456,取 abc123
  • t:毫秒时间戳
  • appKey:H5 端固定 12574478(不同端不同值,App 端是另一套)
  • data:业务参数的紧凑 JSON 字符串

公式简单到令人发指,但这套体系的精髓不在算法,在 token 的生命周期管理

token 的"过期-刷新"循环

_m_h5_tk 不是登录才有的,匿名访问也会下发。它的获取方式很鸡贼:你直接请求接口,它故意返回令牌过期,同时在响应头里种新 token

响应: {"ret":["FAIL_SYS_TOKEN_EXOIRED::令牌过期"]}
响应头: Set-Cookie: _m_h5_tk=abc123_def456; ...

所以完整的客户端必须实现这个循环:

import hashlib, json, time, requests

class MtopClient:
    def __init__(self):
        self.session = requests.Session()
        self.app_key = '12574478'

    def _token(self):
        tk = self.session.cookies.get('_m_h5_tk', domain='.taobao.com')
        return tk.split('_')[0] if tk else ''

    def request(self, api, data, v='1.0', retry=True):
        t = str(int(time.time() * 1000))
        data_str = json.dumps(data, separators=(',', ':'))
        sign = hashlib.md5(f"{self._token()}&{t}&{self.app_key}&{data_str}".encode()).hexdigest()
        resp = self.session.get(
            f'https://h5api.m.taobao.com/h5/{api}/{v}/',
            params={'jsv': '2.7.4', 'appKey': self.app_key, 't': t, 'sign': sign,
                    'api': api, 'v': v, 'type': 'originaljson', 'dataType': 'json',
                    'data': data_str}
        )
        ret = resp.json()
        if any('TOKEN_EXOIRED' in r or '令牌过期' in r for r in ret.get('ret', [])):
            if retry:
                return self.request(api, data, v, retry=False)  # cookie 已自动种下新 token
        return ret

注意 retry=False 防死循环——刷新后再失败就是别的问题了。

精髓:六个实测坑点

  1. data 序列化是头号杀手。必须 separators=(',', ':') 紧凑无空格,key 顺序保持接口定义原样(Python dict 保序,按抓包顺序构造即可)。多空格、换行、key 乱序,签名全废。调试时把浏览器抓的 data 原文和你的生成结果做字符串 diff。
  2. appKey 分端不通用。H5 是 12574478,但同一个接口在 App 端是另一个 appKey,token 体系也不同。跨端抄参数必挂。
  3. _m_h5_tk 有配套兄弟 _m_h5_tk_enc。部分敏感接口两个都校验,清 cookie 时要一起处理。
  4. 域名体系。接口域名是 h5api.m.taobao.com,但 cookie 种在 .taobao.com 域。天猫业务走 h5api.m.tmall.com,token 不通用。
  5. 签名对了只是入场券。高频请求会触发 FAIL_SYS_ACCESS_DENIED 或要求滑块验证(x5sec 体系),那是行为风控,签名层无解,只能控速 + 代理池。
  6. type 参数影响返回格式originaljson 返回纯 json,jsonp 返回回调包裹——协议模拟用前者,别给自己找解析麻烦。

一个完整的调试方法论

签名不对时按这个顺序排查:

  1. 抓浏览器真实请求,把 data 参数原文复制出来,和你的 data_str 逐字符对比
  2. 确认 token 是下划线前段,没把 _def456 部分算进去
  3. 确认 t 和 sign 用的是同一个 t(有人犯过签名用 t1、参数传 t2 的低级错误)
  4. 以上都对还失败,换一个全新会话重走"过期-刷新"流程,排除 token 污染

总结

  1. 公式 md5(token&t&appKey&data) 十分钟实现,核心是 token 的过期-刷新循环
  2. data 紧凑 JSON、key 保序,是 90% 签名失败的原因
  3. appKey、token、域名三者成套,跨端不通用
  4. x5sec 滑块是另一套体系,签名解决不了,靠控速和代理
By 百趣云 阅读量:1 On