11 KiB
虎牙网页 Cookie 合并审计与来源矩阵
更新时间:2026-09-01
结论
core/huya/app_login.py::_merge_web_cookie 只应合并当前登录流程实际得到的认证值和已有网页 Cookie。Cookie 在抓包中出现,不代表可以凭长度或字符集在本地生成。
9.1 抓包中,活动 WSS 的角色查询和积分查询均成功,说明活动接口当前主要依赖核心认证字段;这不能证明随机设备字段、商城接口和支付链路会接受伪造值。
字段来源
| 字段 | 真实来源 | 当前策略 |
|---|---|---|
udb_cred |
App WUP 登录响应的 114B cred,Base64URL 后 152 字符 |
本次值覆盖旧值 |
udb_uid、yyuid |
WUP 登录响应解析出的真实 UID | 本次值覆盖旧值 |
udb_biztoken |
tryQrLogin(stage=2) 响应 |
本次值覆盖旧值 |
udb_passport、username |
网页 Cookie/tryQrLogin/App 登录态中的真实 passport | 只有输入本身是 hy_ 账号时才写入,否则保留已有值 |
udb_version、udb_origin、udb_status |
网页登录协议固定字段 | 写入协议固定值 |
sdid、hdid |
df/collect 的 Set-Cookie/响应 |
本次指纹响应覆盖旧值 |
guid |
网页/launch 会话的 GUID32 | 只接受显式 device_info["guid"] 或 Session 值 |
udb_guiddata |
浏览器设备状态字段,和 guid 是不同值 |
只接受显式值,不再与 guid32 复制 |
game_did、__yamid_*、QIMEI、udb_anobiztoken |
浏览器/设备 SDK 状态,部分具有关联或签名 | 无真实值时省略 |
udb_deviceid |
浏览器设备 Cookie | 只接受格式正确且显式提供的值 |
Hm_*、HMACCOUNT、*_rep_cnt、_yasids |
页面统计与访问计数状态 | 只保留已有或显式提供值 |
9.1 抓包事实
同一网页会话内这些值保持稳定:
_qimei_uuid42:42 位;_qimei_h38:38 位;_qimei_fingerprint:32 位。三者是 QIMEI 设备标识,不能用随机十六进制替代。udb_anobiztoken:344 位 URL-safe 字符串,和udb_anouid共同属于匿名设备状态,不能用重复 UUID 字节拼接。guid与udb_guiddata均为 32 位,但抓包值不同,不能复用同一画像字段。udb_deviceid为w_加 19 位数字;格式可以校验,但仅凭格式无法得到真实值。huya_flash_rep_cnt、huyasp_rep_cnt、huya_hd_rep_cnt、huya_web_rep_cnt随访问过程变化,不能硬编码抓包历史值。
抓包中还存在 huya_ua,它是 WSS/HTTP RPC 的业务 UserId 字段,不属于持久化 Cookie;由 wss_client.py 和 http_client.py 按通道注入。
旧实现的问题
旧实现曾在空 Session 中生成 __yamid_new、game_did、三个 QIMEI 字段、udb_anobiztoken、HMACCOUNT、_yasids 和多个固定计数器。它们只能满足长度测试,不能证明值具有协议语义。
旧实现还把 device_info["guid32"][:32] 同时写入 guid 和 udb_guiddata,并把手机号直接写入 udb_passport/username。这两点会造成设备身份和账号映射偏差。
验证要求
- 登录后必须检查
udb_cred、udb_biztoken、UID、sdid、hdid的来源和值覆盖关系。 - 活动 WSS、商城 WSS、下单和支付分别验证,不能用角色查询成功替代全流程验证。
- 新增 Cookie 字段前,必须有同一会话的响应、页面状态或设备 SDK 输出作为来源证据;只有长度/正则证据时保持省略。
9.1 抓包新增证据
705-meta.json 的 GET www.huya.com/30596253 在请求发出时已经携带 43 个网页 Cookie,
包括 guid、game_did、三个 QIMEI、udb_guiddata、udb_deviceid、udb_anobiztoken
和统计字段;该响应没有 Set-Cookie。随后 714-meta.json 的
POST df.huya.com/web/df/collect 只返回 sdid、hdid 两个 Set-Cookie。
因此 App 的 /web/cookie/verify 不能兑换出完整网页 CK。网页设备字段来自浏览器此前
持久化的 Cookie/Storage 和页面脚本运行态;当前 Python App 登录链不应声称能凭空补齐它们,
也不在脚本中外挂浏览器。2026-09-01 起接入匿名设备态协议
(core/huya/anon_device.py,middle + anonymousLogin)补 udb_deviceid/
udb_guiddata/udb_anobiztoken/udb_anouid 四个字段;其余脚本字段(guid/
game_did/_qimei_uuid42/__yamid_new)缺失时不再拒绝登录,改为警告并保存
(风控风险自担);精英宝典任务不再回退 HTTP。
运行时复核(2026-09-01)
当前 Node 指纹运行器已接入 __COOKIES__ 输出桥:只有 hydevice 通过
document.cookie 实际写入的值才会进入 HuyaSdidResult.cookies,并在合并阶段按
显式值转发。对当前内置 hydevice-prod-1.2.45-min.js 的实际运行结果为:
__SDID__和__HDID__正常返回;- Cookie 桥只观察到脚本自身的
udb_appid/临时sdid,没有生成guid、QIMEI、udb_guiddata、udb_deviceid或udb_anobiztoken; - 因此这次改动此前不会改变
COOKIE_INCOMPLETE判定,也不会用随机值补齐字段; 2026-09-01 登录链接入匿名设备态协议后可补齐 4 个服务端签发字段(见下节)。
从线上下载的 hydevice-prod-1.2.51-min.js 在现有 Node 仿真环境中还依赖未实现的
浏览器 API(首个错误为 window[t(...)] is not a function),没有将其替换进生产链。
后续若升级仿真环境,必须先观察到真实 Cookie 写入,再纳入合并逻辑。
多抓包交叉核验
8.31/reqable完整抓包-1.har:首次页面请求和 QR 请求均已携带全部 7 个字段; QR 成功响应只新增udb_cred、udb_uid、yyuid、udb_passport、username、udb_version、udb_biztoken、udb_origin、udb_status。8.31/cahrles完整抓包-1.har:第一个带网页设备态的请求早于df/collect和 QR 成功响应;df/collect只下发sdid、hdid。7.5-短信登录-滑块.har:web/cookie/verify前后的请求也没有新增这 7 个字段。
因此当前日志中的缺失列表是协议事实,不是 Cookie 合并阶段丢失;服务端正式签发 接口已找到并接入登录链(middle + anonymousLogin,见“匿名流程解密”节)。
真实浏览器实测(2026-09-01,未登录)
用真实 Chrome(有头)通过 CDP 抓包复核,两轮验证:
core/huya/browser_harvest.py(round1 全新 profile / round2 同 profile 重启),
原始数据与报告在 evidence/browser_cookie_harvest/。
页面序列:www.huya.com 门户 → 直播间 30596253,全程不登录。
| 字段 | 首次出现位置 | 产生机制 | round2 重启后首请求携带 |
|---|---|---|---|
__yamid_new |
liveapi.huya.com/ip/getIpLocation (XHR) |
门户页脚本写 document.cookie |
✅ |
game_did |
同上 | 脚本写入 | ✅ |
udb_guiddata |
udblgn.huya.com/web/middle/2.4/... (Document) |
UDB SDK 脚本写入,与 guid 值不同 |
✅ |
guid |
udbres.huya.com/js/HyUDBWebSDK-Exchange-2.4.js |
UDB SDK 脚本写入 | ✅ |
_qimei_uuid42 |
同上 | QIMEI SDK 脚本写入 | ✅ |
udb_deviceid |
udblgn.huya.com/web/middle/2.4/... 与 /web/anonymousLogin 的 Set-Cookie |
服务端匿名接口下发,w_+19 位数字,10 年 |
✅ |
udb_anobiztoken |
udblog.huya.com/web/log/report |
UDB SDK 脚本写入 | ✅ |
结论:
- 7 个必填字段全部由浏览器页面运行态产生(6 个脚本写
document.cookie,1 个udb_deviceid由匿名服务端接口下发),与登录协议无关 ——COOKIE_INCOMPLETE判定是协议事实。 - round2 重启后门户首 Document 请求直接携带 16 个 Cookie(7 个必填字段全部在内), 证明这些字段是浏览器持久态,跨会话稳定复用。
- 首次访问时序:门户首请求无 Cookie → 脚本热启动后
__yamid_new/game_did先出现 → UDB SDK 加载后guid/udb_guiddata/QIMEI 出现 →anonymousLogin匿名 XHR 携全套字段并把udb_deviceid种回 10 年。 - 全会话服务端
Set-Cookie仅PHPSESSID、udb_deviceid、sdid、HMACCOUNT(百度统计)、mediavv五类,其余全部来自脚本。
新突破口:udblgn.huya.com/web/anonymousLogin 与 /web/middle/2.4/... 是公开
匿名接口(纯 HTTP 可调),服务端正式签发 udb_deviceid —— 这是“服务端正式签发
接口”的第一个实例;guid/QIMEI/udb_anobiztoken 仍无服务端下发,只能靠复刻
页面 SDK(HyUDBWebSDK-Exchange-2.4.js 等)的脚本语义。
匿名流程解密(2026-09-01,纯 HTTP 复放验证)
浏览器实际匿名链(未登录):
GET udblgn.huya.com/web/middle/2.4/<8位随机>/https/<32hex>→Set-Cookie: udb_deviceid=w_<19位>; Max-Age=315360000; Domain=huya.com, 响应是一个加载HyUDBWebSDK-Exchange-2.4.js并init()的引导 HTML。- SDK 随后发
POST udblgn.huya.com/web/anonymousLogin(Content-Type: application/json,Referer必须为 middle URL, 否则返回error!):- 请求体
{"uri":"10013","version":"2.4","context":"WB-<hex32>-<hex32>-<hex32>", "appId":5002,"sdid":"csid_<hex32>","lcid":2052,"byPass":3, "requestId":<8位>,"authId":"","data":{"domainList":""}} - 响应
returnCode:0:data.uid(12 位匿名 uid)、data.biztoken(344 位 URL-safe)、Set-Cookie: udb_anouid(7 天)+udb_deviceid。
- 请求体
- 页面 SDK 把
biztoken写入udb_anobiztoken、uid写入udb_anouid, 与 middle URL 的 32hex(=udb_guiddata)、guid、QIMEI、__yamid_new、game_did一起构成网页设备态。
对照验证(真实浏览器最终 Cookie 与响应值一一对应):
| Cookie | 值形态 | 来源 |
|---|---|---|
udb_deviceid |
w_+19 位数字 |
middle/anonymousLogin Set-Cookie(10 年) |
udb_anobiztoken |
344 位,AQA… 开头 |
anonymousLogin 响应 data.biztoken |
udb_anouid |
12 位数字 | anonymousLogin 响应 data.uid/Set-Cookie(7 天) |
udb_guiddata |
32hex | middle URL 的第三段参数(客户端自选) |
guid |
32hex | 页面 SDK 脚本写入 document.cookie |
_qimei_uuid42 |
42 位 | QIMEI SDK 脚本写入 |
__yamid_new |
32hex | 门户业务脚本写入 |
game_did |
35 位 | 门户业务脚本写入 |
复放实验结论(2026-09-01):
- middle 的 8 位随机数与 32hex 均不校验:任意随机值 GET 即签发新的
udb_deviceid(returnCode 200); - anonymousLogin 的
context/csid/requestId均为全新随机值时,无任何 Cookie 直接 POST 也返回returnCode:0+ 新biztoken与Set-Cookie; - 因此
udb_deviceid、udb_anobiztoken、udb_anouid、udb_guiddata四个字段可由纯协议生成,不再依赖真实浏览器脚本; - 剩余
guid、_qimei_uuid42、__yamid_new、game_did没有服务端签发, 服务端是否校验其“真实性/关联性”未知 ——200只代表接口接受,不代表 风控认可。必须用协议生成的设备态跑通线上 活动 WSS/商城/支付 全链路 才能作为最终结论,不能只凭长度测试(与本文开头结论一致)。