Files
live-hub-py/docs/HUYA_WEB_FIELD_TRACE.md
T

154 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 虎牙网页设备字段溯源(历史证据,2026-09-01 浏览器实测)
> 当前实现状态以 [HUYA_COOKIE路线状态.md](HUYA_COOKIE路线状态.md) 为准;本文保留原始浏览器证据与算法推导。
## 一、来源判定方法(有头 Chrome + 打点探针)
- `Page.addScriptToEvaluateOnNewDocument` 拦截 `Document.prototype.cookie` setter,
记录每条写入的 值/时间/调用栈(栈中含脚本 URL + 行号)。
- `Network.responseReceivedExtraInfo` 捕获服务端 **Set-Cookie** 头。
- 全新 profile,导航 www.huya.com + 直播间页,静置后导出。
## 二、决定性结论:哪些字段服务端下发,哪些浏览器生成
### ✅ 服务端 Set-Cookie 下发(仅 5 个)
| 字段 | 实测 |
| --- | --- |
| `PHPSESSID` | l.web.huya.com / l.huya.com |
| `udb_deviceid` | udblgn.huya.com(`w_` + 19 位数字,匿名设备) |
| `sdid` | udblgn.huya.com(`0UnHUgv0_qmfD4KA...` 设备指纹) |
| `v` | 页面版本 |
| `HMACCOUNT` | 百度统计 |
### ✅ 浏览器脚本 document.cookie 写入(铁证:调用栈)
| 字段 | 生成脚本 | 关键位置 |
| --- | --- | --- |
| `guid` | `a.msstatic.com/huya/main3/npm..pnpm-d84ecac2_850fe68b.js` `Object.setCookie` | 写入 5 次;**位置 12-16 固定 `966a`(跨会话一致)** |
| `_qimei_fingerprint` | `staticfile.qq.com/qimei/qimeisdk-web/0.6.3/index.js` | 写入 1 次 |
| `udb_passdata` | `a.msstatic.com/huya/main3/common/headerfunction_d8b3ad0c.js` `writeCookie` | 固定值 3 |
| `__yasmid` / `__yamid_tt1` | 页面脚本 | 同值 17 位小数 |
### ⚠️ 浏览器生成但**非 document.cookie 写入**(走 Cookie Store API / localStorage 同步等)
| 字段 | 证据 | 说明 |
| --- | --- | --- |
| `__yamid_new` | 88 条写入中无此 key,但最终 cookie 有值 | **CBCC 前缀 + 递增种子**(见下) |
| `game_did` | 同上 | 30-35 位字母数字 |
| `_qimei_uuid42` | 同上 | `1a` 前缀 + 32hex UUID 结构 + 10hex |
## 三、设备字段结构规律(真实样本)
### guid = `0a` + 10hex + `956a`/`966a` + 16hex —— 有固定段,非纯随机
```
0a7dfa5fc9ee966aab02a2eaa3ea1de1 ← live 窗口
0a7dfaa2d7af966a2101f370f470ce50 ← round2 fresh
0a7de265986f956a24015b505c504506 ← reqable 8.31
0a89d5f6614b956aa6020bbc0cbc18fe ← cahrles 8.31
```
位置 12-16 恒为 `956a` / `966a`(产品段?),8.31 为 `956a`、我们机器为 `966a` ——
可能与 SDK/页面版本有关。
### __yamid_new = `CBCC`/`CBCB` + 种子6hex + 计数4hex + `0001` + 随机12hex
```
CBCC 6479D9 B000 0001 52EC19001D2017B2 ← live 窗口
CBCC 551C11 E000 0001 783D8F5530901BCC ← round2 fresh
CBCC 06ECB5 0000 0001 B63016D6162BC990 ← reqable 8.31
```
- 前缀 `CBCC`/`CBCB` 恒定(产品标识)
- 种子段递增且与 `_yasids`(rootsid)**同源共享时钟**:
`yamid=CBCC6479D9B0...` ↔ `rootsid=CBCC647A8A20...`(同会话,种子差 0xB1≈177)
- `0001` 固定,尾部大段随机
### _qimei_uuid42 = `1a` + 40hex(32hex UUID 结构 + 10hex 附加)
```
1a81f140c08100b89fb1be450f640501568684b2ea ← reqable 8.31
1a901123a1f10045427c1c73420287f44f49d11b45 ← round2 fresh
1a901171b051007527940c2acef15dcd2342b6ff ← live 窗口
```
首字节 `1a` 恒定;前 32 hex 符合 RFC 4122 UUID 布局(8-4-4-4-12)。
### _qimei_fingerprint = x64hash128(feature_string, 31) 32hex
qimeisdk-web 0.6.3 源码已定位:
- 画 "qimei" 文本(Times New Roman 11pt)+ `#f60` 背景 + 透明度矩形
- 三圆叠加(`#f2f`/`#2ff`/`#ff2` 40 半径)+ 环形 `#f9c` evenodd
- Canvas `id`/`geometry` 是 SDK 特征对象的独立字段;Cookie 指纹实际使用浏览器能力特征串
→ SDK 内置 **x64hash128**(seed=31)→ 32hex。
## 四、溯源结论与建议
| 字段 | 来源 | 风控关联性 | 建议 |
| --- | --- | --- | --- |
| `guid` | 浏览器脚本(有固定段 `0a..966a`)| 高(设备与会话绑定) | **必须按结构仿造或复用 wsLaunch 会话值**;随机纯 hex 与真实结构不符 |
| `__yamid_new` | 浏览器脚本(CBCC 前缀+种子)| 高(与 rootsid 同源)| `room_normal.js` `generate32` 已复刻;精确 rootsid 共享计数仍待确认 |
| `_qimei_uuid42` | QIMEI SDK 0.6.3(`1a` 前缀)| 中 | 前缀 `1a` + UUID 布局 |
| `_qimei_fingerprint` | QIMEI SDK 0.6.3 x64hash128(feature_string, 31) | 中 | Python 已复刻,输入字段见路线状态文档 |
| `game_did` | 浏览器脚本 | 中 | 长度需对齐(35 变体含 `-`)|
| 统计字段(SoundValue 等)| 页面脚本 | 低 | 随机 OK |
**当时的下一步记录(部分已完成,保留作历史)**:
1. `_qimei_fingerprint` 已改为浏览器能力特征串的 `x64hash128`,见路线状态文档。
2. `guid` 已优先使用 `wsLaunch` 会话值,回退固定段仍待确认。
3. `__yamid_new` 已定位 `room_normal.js` `generate32` 并完成 Python 复刻。
## 六、核心字段生成算法逆向结果(2026-09-01 晚,浏览器实测 + 源码定位)
### ✅ __yamid_new = room_normal.js generate32(UUID-v1 风格,已 Python 复刻验证)
```js
// a.msstatic.com/huya/main3/app/room_normal_55c7cc4f.js
function u(e){var t="__yamid_new",n=getCookieVal(t);if(n)return n;n=e||d.generate32();...writeCookie(t,n,...)}
d.generate32(){
c = new Date().getTime() - new Date(1582,10,15,0,0,0,0).getTime(); // 本地时区 epoch
return generateBits(c,0,31) // time_low 8hex
+ generateBits(c,32,47) // time_mid 4hex
+ generateBits(c,48,59)+"1" // time_hi+版本位
+ generateBits(rand(4095),0,7) + generateBits(rand(4095),0,7)
+ generateBits(rand(8191),0,7)+... 48位随机node;
}
```
- 浏览器实测 epoch(GMT+8): `-12216643543000`;Python 复刻 12hex 时间戳段与浏览器**逐位一致**
- **`CBCC` 前缀是时间戳自然结果**(1582-epoch 当前值的高位),非固定魔数;随生成时刻缓慢递增
- `_yasids`(rootsid)同源同刻生成(浏览器实测 yamid=`CBCC653E4B...` / rootsid=`CBCC647A8A...` 共享种子时钟)
### ✅ game_did = vplayerUI.js 35 位随机(已复刻)
```js
// a.msstatic.com/huya/h5player/room/2608311423/vplayerUI.js
B = (t=35) => { const e="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
for(i="";i.length<t;) i += e.charAt(parseInt(Math.random()*(e.length-1))); return i }
```
- **长度 35**(旧随机 30 位是错的);字符集 64 去掉末尾 `_`(63 选 1)
- cookie 名 `game_did`,无 cookie 时生成并写入
### ⚠️ _qimei_uuid42 结构已定,算法待深挖
- cookie 值:首字节 `1a` 固定 + 40hex(localStorage 是 44hex,cookie 为截断子串)
- 由 qimeisdk-web 0.6.3 内部 VM 生成(`_qimei_ssid`/`_qimei_last_get_id_time_<16hex>` 同源)
- 当前实现对齐结构(1a 前缀 + 42hex 随机化),精确算法待继续
### ✅ _qimei_fingerprint = x64hash128(feature_string,31),已完成 Python 复刻
- Cookie 输入由屏幕分辨率、浏览器能力、WebGL 和时区字段按 `###` 拼接。
- Python 实现位于 `core/huya/web_cookie_fields.py`,测试向量与 SDK 输出一致。
- 没有实时浏览器能力对象时,生成器使用稳定的默认 Web 特征档案。
### 已修正生成器(core/huya/web_cookie_fields.py)
- `__yamid_new` → `_yamid_new_generate32()`(UUID-v1 时间戳复刻)
- `game_did` → `_game_did_generate()`(35 位 63 字符集)
- `_yasids` → 与 `__yamid_new` 同源同刻生成
- `_qimei_uuid42` → `1a` 前缀 + 42hex
- `guid`(无会话值回退)→ `0a` + 10hex + `966a` + 16hex 结构
## 七、逆向生成器端到端验证(2026-09-01 晚,账号 18397482576 重新登录后)
新版生成器(web_cookie_fields.py commit 8fef04d)产出字段:
- guid=`0a43b01a366c966a7fe26a281e1d3c88`(0a 前缀 + 966a 固定段)
- __yamid_new=`CBCC65D6C5200001F176114BCF181E25`(UUIDv1 时间戳)
- _qimei_uuid42=`1a552b4b...`(1a 前缀)
- game_did=35 位
- _yasids 与 yamid 同源(CBCC65D6C5 前缀一致)
webActUI 全链路 status=200:
1. checkUserBindGameAccount → 和平精英/痛仰之吻
2. getUserScore → gain=5580 available=280
3. getActPrizeList → 29 商品
4. **scoreExchangePrize → status=200 真实兑换成功**
(荣耀勋章礼包(小)20 分,订单 sOrderId_2203_12855_1199667330433_...)
5. getUserPrizeRecords → 4 条
↑ 之前 getConfig 超时是旧 cookie 过期(id58 已清空),非生成器问题。