luckfun233 commited on
Commit ·
ee56648
1
Parent(s): 5db4eb7
feat: 更新Web端接口文档,补充数美风控升级后的协议细节与失败分类说明
Browse files
docs/shumei-device-id-research.md
CHANGED
|
@@ -1,9 +1,18 @@
|
|
| 1 |
# 数美(Shumei)SDK 逆向研究报告
|
| 2 |
|
| 3 |
> 研究目标:DeepSeek Web端登录所需的 device_id 生成算法
|
| 4 |
-
> 研究时间:2026-06-09
|
| 5 |
> 项目位置:d:\ds2api
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
---
|
| 8 |
|
| 9 |
## 一、SDK 基本信息
|
|
@@ -39,6 +48,8 @@ appId (测试环境): wx58f1d4bc57bc28fd / wxd4679ecc940ea6be
|
|
| 39 |
|
| 40 |
## 三、device_id 生成完整流程
|
| 41 |
|
|
|
|
|
|
|
| 42 |
```
|
| 43 |
┌─────────────────────────────────────────────────────┐
|
| 44 |
│ 1. 初始化 │
|
|
@@ -680,3 +691,173 @@ Python 工具依赖 `pycryptodome`(`pip install pycryptodome`)。
|
|
| 680 |
`response/fragments/-1` 下的 `{p:"status", v:"FINISHED"}` 是**片段级状态**,
|
| 681 |
不是整条流结束;把它当成 `response/status` 会让联网模式在搜索阶段提前终止、
|
| 682 |
正文为空。片段类型与解析规则见 `deepseek-recall-research.md` 附录 C。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# 数美(Shumei)SDK 逆向研究报告
|
| 2 |
|
| 3 |
> 研究目标:DeepSeek Web端登录所需的 device_id 生成算法
|
| 4 |
+
> 研究时间:2026-06-09(初版,旧协议) / 2026-09-25(推翻重写,见 §15–§17)
|
| 5 |
> 项目位置:d:\ds2api
|
| 6 |
|
| 7 |
+
> ⚠️ **阅读指引(重要)**
|
| 8 |
+
> 本文档第一至第十四节记录的是 **2026-06 的旧版协议**(ConfusionInfo + protocol=-1/4),
|
| 9 |
+
> 该协议已于 2026-09 被数美废弃,照其实现在服务端会得到 `1902`、登录会得到
|
| 10 |
+
> `RISK_DEVICE_DETECTED`。**当前生效的协议与项目实现请看:
|
| 11 |
+
> [§15 新版协议](#十五2026-09-风控升级新版-sdkprotocol279)、
|
| 12 |
+
> [§17 风控结构详解(系统视角)](#十七新版风控结构详解系统视角)、
|
| 13 |
+
> [§16 复现手册](#十六复现手册工具链--坑位清单)。**
|
| 14 |
+
> 旧章节仅作历史参考与"变化对比"用。
|
| 15 |
+
|
| 16 |
---
|
| 17 |
|
| 18 |
## 一、SDK 基本信息
|
|
|
|
| 48 |
|
| 49 |
## 三、device_id 生成完整流程
|
| 50 |
|
| 51 |
+
> ⚠️ 本节为**旧协议**流程(2026-06)。新版流程见 §15.4,系统视角总览见 §17.1。
|
| 52 |
+
|
| 53 |
```
|
| 54 |
┌─────────────────────────────────────────────────────┐
|
| 55 |
│ 1. 初始化 │
|
|
|
|
| 691 |
`response/fragments/-1` 下的 `{p:"status", v:"FINISHED"}` 是**片段级状态**,
|
| 692 |
不是整条流结束;把它当成 `response/status` 会让联网模式在搜索阶段提前终止、
|
| 693 |
正文为空。片段类型与解析规则见 `deepseek-recall-research.md` 附录 C。
|
| 694 |
+
|
| 695 |
+
---
|
| 696 |
+
|
| 697 |
+
## 十七、新版风控结构详解(系统视角)
|
| 698 |
+
|
| 699 |
+
> 本节回答"这套风控到底是怎么运作的":谁校验谁、校验什么、失败了怎么表现。
|
| 700 |
+
> 协议字段级的细节在 §15,本节讲结构与语义。
|
| 701 |
+
|
| 702 |
+
### 17.1 参与方与数据流
|
| 703 |
+
|
| 704 |
+
风控不是"数美单独一道题",而是 **数美签发设备身份 → DeepSeek 侧据此判定风险** 的两段式:
|
| 705 |
+
|
| 706 |
+
```
|
| 707 |
+
① 前端(或本项目的 Go 实现)
|
| 708 |
+
│ 采集环境指纹 + 本地 SMID
|
| 709 |
+
▼
|
| 710 |
+
② 数美 deviceprofile/v4 ── 校验「数据完整性 + 指纹合理性」
|
| 711 |
+
│ 通过 → 签发 SMID(deviceId)
|
| 712 |
+
│ 不通过 → 1902(数据不合法,需重做)
|
| 713 |
+
▼
|
| 714 |
+
③ device_id = "B" + SMID ── 存入 localStorage 复用,登录时随请求体提交
|
| 715 |
+
▼
|
| 716 |
+
④ DeepSeek /api/v0/users/login ── 校验「device_id 是否为数美真实签发 + 是否已被标记」
|
| 717 |
+
│ 通过 → biz_code=0,返回 user.token
|
| 718 |
+
│ 不被信任 → biz_code=11 / RISK_DEVICE_DETECTED
|
| 719 |
+
▼
|
| 720 |
+
⑤ 拿到 token 后的所有业务接口(会话、PoW、completion、文件…)
|
| 721 |
+
```
|
| 722 |
+
|
| 723 |
+
两个关键推论:
|
| 724 |
+
- **②失败(1902)必然导致④失败**。设备身份拿不到,登录就没有可信 device_id。
|
| 725 |
+
- **④失败不一定代表②失败**。设备可能签发成功但已被风控标记(账号维度/设备维度),
|
| 726 |
+
此时唯一可控手段是换一个设备身份(本项目即"重签一次")。
|
| 727 |
+
|
| 728 |
+
### 17.2 端点与主机映射
|
| 729 |
+
|
| 730 |
+
| 用途 | 端点 | 说明 |
|
| 731 |
+
|------|------|------|
|
| 732 |
+
| 设备画像上报(Web) | `https://fp-it-acc.portal101.cn/deviceprofile/v4` | DeepSeek web 端使用,本项目走这条 |
|
| 733 |
+
| 数美备用主机族 | `fp-it.fengkongcloud.com` 等 | 换主机无效,报文格式一致;Android 原生 SDK 走独立协议 |
|
| 734 |
+
| 登录 | `https://chat.deepseek.com/api/v0/users/login` | 请求体含 `device_id` + `os` |
|
| 735 |
+
| 设备注册/轮换 | `check_device`(登录后调用) | 真实客户端会调,含 `rotate` 语义(本项目未实现) |
|
| 736 |
+
|
| 737 |
+
### 17.3 device_id 生命周期与失败分类
|
| 738 |
+
|
| 739 |
+
```
|
| 740 |
+
[无 device_id] --签发--> [已签发 SMID 落盘] --复用--> 每次登录沿用同一个
|
| 741 |
+
│
|
| 742 |
+
└--登录返回 RISK_DEVICE_DETECTED--> 重签一次并覆盖
|
| 743 |
+
```
|
| 744 |
+
|
| 745 |
+
| 现象 | 层级 | 含义 | 处理 |
|
| 746 |
+
|------|------|------|------|
|
| 747 |
+
| 数美返回 `code=1100` | ② | 画像合法,返回 `detail.deviceId` | 取 `"B"+deviceId` 使用 |
|
| 748 |
+
| 数美返回 `code=1902` | ② | 数据不合法(协议号/字段集/tn/编码不对) | 修正构造逻辑后重试(本项目自动重试 3 次) |
|
| 749 |
+
| 登录 `biz_code=0` | ④ | 设备可信,登录成功 | 保存 `user.token` |
|
| 750 |
+
| 登录 `biz_code=11` / `RISK_DEVICE_DETECTED` | ④ | 设备身份不可信 | 重签 device_id 后重试一次 |
|
| 751 |
+
| 登录 `missing login token` | ④ | `biz_code=0` 但 `biz_data.user.token` 为空 | 通常也是风控拦截的表现,按风险失败处理 |
|
| 752 |
+
|
| 753 |
+
> 注意:`missing login token` 与 `RISK_DEVICE_DETECTED` 是**同一根因的两种表现**,
|
| 754 |
+
> 前者出现在响应结构异常(如 android 端),后者出现在业务码明确拒绝时(如 web 端)。
|
| 755 |
+
|
| 756 |
+
### 17.4 完整字段清单(80 项)
|
| 757 |
+
|
| 758 |
+
明文的 58 项 + ��密的 22 项。加密字段的密钥见 §15.2 与
|
| 759 |
+
`internal/shumei/confusion.go` 的 `fieldDESKey`。
|
| 760 |
+
|
| 761 |
+
**① 基础字段(9 项,身份与版本)**
|
| 762 |
+
|
| 763 |
+
| 字段 | 明文值 | 加密 |
|
| 764 |
+
|------|--------|------|
|
| 765 |
+
| `protocol` | `279` | 明文 |
|
| 766 |
+
| `cm` | organization `P9usCUBauxft8eAmUXaZ` | ✓ |
|
| 767 |
+
| `og` | appId `default` | ✓ |
|
| 768 |
+
| `ki` | `web` | ✓ |
|
| 769 |
+
| `version` | `3.0.0` | 明文 |
|
| 770 |
+
| `ek` | sdkver `3.0.0` | ✓ |
|
| 771 |
+
| `yp` | subVersion `1.0.0` | ✓ |
|
| 772 |
+
| `xy` | rtype `all` | ✓ |
|
| 773 |
+
| `kd` | 服务端下发 SMID(首次为空) | 明文 |
|
| 774 |
+
|
| 775 |
+
**② 时间与随机标识(8 项)**
|
| 776 |
+
|
| 777 |
+
| 字段 | 含义 | 加密 |
|
| 778 |
+
|------|------|------|
|
| 779 |
+
| `aw` / `jt` | 随机 UID(UUID v4),`jt` 与 `smid` 同源 | ✓ / ✓ |
|
| 780 |
+
| `hk` / `xv` | 采集时间戳(毫秒,两者相差约 1ms) | ✓ / ✓ |
|
| 781 |
+
| `yi` | 页面加载至今的毫秒数 | ✓ |
|
| 782 |
+
| `t` | 采集时刻(毫秒时间戳) | 明文 |
|
| 783 |
+
| `collectTime` | 采集耗时(毫秒) | 明文 |
|
| 784 |
+
| `smid` | 本地 smidV2(`yyyyMMddHHmmss`+md5(uid)+…) | 明文 |
|
| 785 |
+
|
| 786 |
+
**③ 环境指纹 — 加密的 11 项**
|
| 787 |
+
|
| 788 |
+
| 字段 | 含义 | 本项目取值策略 |
|
| 789 |
+
|------|------|----------------|
|
| 790 |
+
| `xo` | userAgent | 与头一致的 Chrome/Edge UA |
|
| 791 |
+
| `tt` | platform | `Win32` |
|
| 792 |
+
| `lp` | clientSize(视口/屏幕尺寸串) | 由分辨率常量拼装 |
|
| 793 |
+
| `vx` | res(分辨率 + 色深 + dpr) | `1920_1080_24_1` |
|
| 794 |
+
| `vr` | canvas 指纹 | 由 uid 派生的稳定 8 位 hex |
|
| 795 |
+
| `sc` | plugins | `-` |
|
| 796 |
+
| `eb` | referer | `https://chat.deepseek.com/` |
|
| 797 |
+
| `wl` | 当前 url | 登录页地址 |
|
| 798 |
+
| `ic` | 时区偏移(分钟) | `-480` |
|
| 799 |
+
| `fu` | status 位串(Flash/cookie/DevTools 等) | `0010` |
|
| 800 |
+
| `er` | tn 完整性校验值 | 由其余字段算出 |
|
| 801 |
+
|
| 802 |
+
**④ 环境指纹 — 明文的 13 项**
|
| 803 |
+
|
| 804 |
+
| 字段 | 含义 | 取值 |
|
| 805 |
+
|------|------|------|
|
| 806 |
+
| `cdp` | Chrome DevTools Protocol 探测 | `1` |
|
| 807 |
+
| `maxTouchPoints` | 触摸点 | `0` |
|
| 808 |
+
| `connectionRtt` | 网络 RTT | `50` |
|
| 809 |
+
| `cpucount` / `fk` | CPU 核数(两个字段同值) | `8` |
|
| 810 |
+
| `battery` | 电池状态对象 | `{charging:1, level:1}` |
|
| 811 |
+
| `incognito` | 无痕模式 14 项探测结果 | 结构化对象 |
|
| 812 |
+
| `ag` | `new Date().toString()` | JS 日期串 |
|
| 813 |
+
| `qg` | 空串 md5 + 65 个 `1` 的指纹串 | 固定格式 |
|
| 814 |
+
| `kv` | IANA 时区名 | `Asia/Shanghai` |
|
| 815 |
+
| `qm` | 颜色/渲染探测 | `{red:"0"}` |
|
| 816 |
+
| `uu` | 触摸能力对象 | `{maxTouchPoints,touchEvent,touchStart}` |
|
| 817 |
+
| `tn` | **document 能力列表**(见下注) | 字符串数组 |
|
| 818 |
+
|
| 819 |
+
**⑤ 其余数值/空串字段(39 项)**
|
| 820 |
+
|
| 821 |
+
`ah`(-1)、`bq`(1)、`cq`(1)、`dn`(0)、`documentExist`(1)、`fe`(1)、`ff`(-1)、
|
| 822 |
+
`fj`(1040)、`gc`、`gy`(0)、`hb`、`hz`、`je`、`jk`、`jo`(0)、`kf`(1920)、`kj`(0)、
|
| 823 |
+
`ks`(1)、`kw`、`ld`、`lr`(0)、`mu`(0)、`ov`、`po`、`pp`(0)、`qa`(0)、`qx`、`rq`([])、
|
| 824 |
+
`ts`(1)、`uo`(-1)、`up`(0)、`uq`(1)、`uy`、`vn`(943)、`vy`(-1)、`xd`({})、`ym`([])、
|
| 825 |
+
`zl`(0)、`zx`(1920)。
|
| 826 |
+
|
| 827 |
+
> 分组核对:① 9 + ② 8 + ③ 11 + ④ 13 + ⑤ 39 = **80 项**(= JSON 实际字段数)。
|
| 828 |
+
> 另有 `yu` 是唯一的**例外项**:值为 `undefined`,不写入 JSON,
|
| 829 |
+
> 但在 tn 拼接中贡献字符串 `undefined`,因此参与 tn 的字段共 81 项。
|
| 830 |
+
|
| 831 |
+
> ⚠️ **字段名冲突**:`tn` 在新协议里是"document 能力列表"(数组,明文),
|
| 832 |
+
> 而**旧协议**的 `tn` 是"完整性校验值"。新版完整性字段改名为 `er`。
|
| 833 |
+
> 读老代码/老文档时务必分清。
|
| 834 |
+
|
| 835 |
+
### 17.5 服务端校验点
|
| 836 |
+
|
| 837 |
+
数美与 DeepSeek 校验的不是"指纹是否与真实浏览器逐位一致",而是这些自洽性:
|
| 838 |
+
|
| 839 |
+
| 校验项 | 说明 | 本项目如何满足 |
|
| 840 |
+
|--------|------|----------------|
|
| 841 |
+
| tn/`er` 自洽 | 拼接串的 md5 必须与 `er` 一致 | 严格复刻 JS 语义(§15.3) |
|
| 842 |
+
| 编码链自洽 | gzip→base64→AES 必须能被服务端解开 | 严格按 §15.4 流水线 |
|
| 843 |
+
| `ep` 可解密 | RSA 必须用数美公钥、输出 base64 | RSA PKCS#1 v1.5 + base64 |
|
| 844 |
+
| 字段格式合理 | UA/分辨率/时区等需为合理值 | 常量取自真实 Windows 环境 |
|
| 845 |
+
| device_id 来源可信 | 必须是数美签发过、未过期的 SMID | 每次签发都真上报换取 |
|
| 846 |
+
| 设备未被标记 | 账号/设备维度的风险名单 | 失败时重签一次 |
|
| 847 |
+
|
| 848 |
+
也就是说:**格式自洽 + 真实签发**才是关键,无需(也不可能)逐位复刻真实浏览器。
|
| 849 |
+
|
| 850 |
+
### 17.6 稳定性评估与退化预案
|
| 851 |
+
|
| 852 |
+
| 风险 | 触发条件 | 表现 | 预案 |
|
| 853 |
+
|------|----------|------|------|
|
| 854 |
+
| 协议再升级 | 数美改字段/密钥/算法 | `1902` 持续出现 | 按 §16.2 七步复现流程重跑一遍 |
|
| 855 |
+
| 新增字段 | 服务端要求新采集项 | `1902` | `capture_payload.js` 输出会直接显示新字段 |
|
| 856 |
+
| 密钥轮换 | 字段密钥变了 | `1902` | `crack_des_keys.py` 重跑回填 |
|
| 857 |
+
| 设备被标记 | 该 SMID 进风险名单 | `RISK_DEVICE_DETECTED` | 已内置自动重签一次 |
|
| 858 |
+
| 环境一致性加强 | 服务端开始比对指纹真实性 | 不确定(暂无先例) | 需按 §17.4 补齐真实采集值 |
|
| 859 |
+
| 部署不可持久化 | config 丢失 | device_id 重签(不失败) | 尽量挂持久化目录 |
|
| 860 |
+
|
| 861 |
+
判断"是协议变了还是设备被标记"的快速方法:
|
| 862 |
+
- 用 `payload.json` 直接 POST 数美接口 → 返回 `1902` ⇒ **协议变了**(走 §16.2)
|
| 863 |
+
- 返回 `1100` 但登录仍被拒 ⇒ **设备/账号被标记**(换账号或等待)
|
docs/web-endpoint-upgrade.md
CHANGED
|
@@ -17,8 +17,9 @@
|
|
| 17 |
| 浏览器特有头 | 无 | sec-ch-ua, origin, referer等 |
|
| 18 |
|
| 19 |
> 2026-09 更新:数美风控升级后,两端登录都改为向数美申请真实签发的 device_id
|
| 20 |
-
> (本地伪造值会被判定为 `RISK_DEVICE_DETECTED`)。
|
| 21 |
-
> `docs/shumei-device-id-research.md` 第十五节
|
|
|
|
| 22 |
|
| 23 |
### 架构设计
|
| 24 |
|
|
|
|
| 17 |
| 浏览器特有头 | 无 | sec-ch-ua, origin, referer等 |
|
| 18 |
|
| 19 |
> 2026-09 更新:数美风控升级后,两端登录都改为向数美申请真实签发的 device_id
|
| 20 |
+
> (本地伪造值会被判定为 `RISK_DEVICE_DETECTED`)。
|
| 21 |
+
> 协议细节见 `docs/shumei-device-id-research.md` 第十五节,
|
| 22 |
+
> 风控整体结构与失败分类见同文档第十七节。
|
| 23 |
|
| 24 |
### 架构设计
|
| 25 |
|