百趣云 百趣云的博客

携程接口签名:从 cookie 到请求头

携程的防护结构:标识体系比签名复杂

逆向携程接口时容易陷入一个误区:把 sign 参数当主角。实际上携程的防护重心在设备标识体系——GUIDclientidUBT 埋点标识、指纹 fp 互相咬合,sign 只是把这些标识串起来的最后一环。先理清标识体系,签名水到渠成。

标识体系拆解

  • GUID:32 位标识,首次访问由服务端 Set-Cookie 种下,长期有效。它是携程体系里的"设备身份证"
  • clientid:请求头里的客户端标识,和 GUID 关联生成
  • UBT 系列:埋点 cookie(_UBT_bfa 等),记录页面行为路径,部分接口会校验其存在性
  • fp:指纹值,独立 SDK 采集生成,和 ua/设备参数绑定

协议模拟的铁律:这些标识成套生成、成套固定。拿 A 设备的 GUID 配 B 设备的 fp,服务端一致性校验直接命中"设备环境异常"。

sign 的定位与结构

携程 H5 的 sign 由 hybrid 框架的 bridge 层生成,定位入口:

// 携程 H5 大量走 hybrid bridge,hook 点选请求封装层
const _open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(m, u) {
    if (u.includes('sign=') || u.includes('/restapi/')) debugger;
    return _open.apply(this, arguments);
};

断下后回溯到 bridge.js 的签名模块,结构是标准的:

  1. 收集 url path、body、时间戳、clientid、GUID
  2. 竖线分隔拼接待签串
  3. HMAC-SHA1(特征常量 0x67452301,在 JS 里搜十进制形式定位)后 hex 大写
  4. 按版本特定的规则截取/变换后输出

密钥分端存储:H5、小程序、App 各一把。H5 的在字符串池里,运行时解密——老规矩,在使用点下断点拿明文,不静态分析解密过程。

请求编排:顺序比参数重要

携程接口对"访问路径"有隐性校验。直接打业务接口容易返回空数据,正确的编排是模拟真实用户路径:

session = requests.Session()
# 1. 先进站,拿 GUID 等基础 cookie
session.get('https://m.ctrip.com/')
# 2. 访问业务频道页,种下频道相关 cookie 和 UBT
session.get('https://m.ctrip.com/html5/flight/')
# 3. 带齐标识打业务接口
resp = session.post('https://m.ctrip.com/restapi/...', 
                    headers={'clientid': cid, 'sign': sign, ...},
                    json=body)

跳过前两步直接第三步,是"参数全对但返回空"的最常见原因。

精髓:四个实战要点

  1. 签名失败无报错。携程对 sign 错误的响应是返回空数据或通用错误页,不明确提示。调试基准:用"查询城市列表"这类公开接口验证签名链路,通了再接业务接口。
  2. GUID 的"养"。新 GUID 直接打敏感接口容易触发验证,先在浏览类接口上"养"一段时间(积累正常访问记录)再上业务,通过率显著提升。
  3. App 端是 native 签名。携程 App 的 sign 在 SO 层(Ctrip 安全库),和 H5 不通用。App 协议走 Frida hook 签名函数的路线,思路同得物/闲鱼。
  4. 国际版(Trip.com)是独立体系。域名、appid、密钥都不同,但算法结构一致——搞定国内版后迁移成本很低。

总结

  1. 携程防护重心在标识体系:GUID、clientid、fp 成套管理是地基
  2. sign 是 HMAC-SHA1 体系,密钥在使用点内存拿
  3. 请求编排模拟真实路径,裸打业务接口必翻车
  4. 调试用公开接口做基准,签名错误无明确报错
By 百趣云 阅读量:2 On