ds2api / docs /web-endpoint-upgrade.md
luckfun233
feat: 新增数美SDK逆向研究报告及Web端接口实现文档
cf4c38d
|
Raw
History Blame Contribute Delete
12.8 kB

Web端接口实现 & 数美SDK逆向研究报告

一、概述

本项目新增了对 DeepSeek Web端接口的支持,可通过设置面板在"Android端"和"Web端"之间热切换,无需重启服务。

核心功能

特性 Android端 Web端
User-Agent DeepSeek/2.1.2 Android/32 Chrome 137 浏览器UA
TLS指纹 Safari Chrome (HTTP/2)
x-client-platform android web
device_id "android_device" 数美SDK加密字符串
x-hif-dliq 动态轮询获取
x-hif-leim 动态轮询获取
浏览器特有头 sec-ch-ua, origin, referer等

架构设计

┌─────────────────────────────────────────────────────────────┐
│                    设置面板 (WebUI)                          │
│              选择: Android / Web 接口平台                     │
└─────────────────────────┬───────────────────────────────────┘
                          │ PUT /admin/settings
                          ▼
┌─────────────────────────────────────────────────────────────┐
│              Handler.applyPlatformChange()                   │
│           DS.SetPlatform("web" / "android")                  │
├─────────────────────────────────────────────────────────────┤
│  1. dsprotocol.ApplyPlatform()    → 切换 BaseHeaders / UA   │
│  2. RefreshTransport()            → 切换 TLS 指纹            │
│  3. hifPoller.Start()/Stop()      → 启动/停止 HIF 轮询       │
└─────────────────────────────────────────────────────────────┘

切换后立即生效,新请求自动使用对应平台的 UA、TLS 指纹、Headers 和 device_id 算法。


二、文件变更清单

新增文件(8个)

文件 说明
internal/deepseek/protocol/constants_web.json Web端协议常量定义
internal/deepseek/hif/hif.go HIF头部轮询器
internal/deepseek/hif/hif_test.go HIF单元测试
internal/shumei/device_id.go 数美SDK device_id生成入口
internal/shumei/crypto.go RSA/DES/AES/MD5/Gzip加密工具
internal/shumei/confusion.go DES字段混淆映射表
internal/shumei/api.go 数美设备指纹API调用
webui/src/features/settings/PlatformSection.jsx 平台切换UI组件

修改文件(18个)

Config层

  • internal/config/config.go — PlatformConfig结构体、PlatformMode()、IsWebPlatform()
  • internal/config/codec.go — JSON序列化支持
  • internal/config/store_accessors.go — Store级访问器
  • internal/config/validation.go — 平台配置校验

Protocol层

  • internal/deepseek/protocol/constants.go — ApplyPlatform()、WebExtraHeaders()、UserAgent()

Transport层

  • internal/deepseek/transport/transport.go — Chrome TLS指纹、NewWithPlatform()

Client层

  • internal/deepseek/client/client_core.go — SetPlatform()、RefreshTransport()、HIF poller集成
  • internal/deepseek/client/client_auth.go — Web端login(数美device_id)
  • internal/deepseek/client/client_completion.go — Web端completion headers
  • internal/deepseek/client/client_continue.go — Web端continue headers
  • internal/deepseek/client/proxy.go — 平台感知代理客户端

Admin API

  • internal/httpapi/admin/shared/deps.go — DeepSeekCaller接口添加SetPlatform
  • internal/httpapi/admin/settings/handler_settings_*.go — 设置保存/读取/热加载

前端

  • webui/src/features/settings/SettingsContainer.jsx — 集成PlatformSection
  • webui/src/features/settings/useSettingsForm.js — 平台表单数据流
  • webui/src/locales/zh.json / en.json — 国际化翻译

三、数美SDK逆向分析报告

3.1 SDK基本信息

  • SDK名称:数美科技(Shumei)DeviceFingerprint Web SDK
  • 版本:3.0.0 / subVersion 1.0.0
  • 加载方式:通过 https://cdn.deepseek.com/static/chat/fp-1.min.js 动态加载
  • 配置来源window._smConf(由DeepSeek页面注入)
  • API端点https://fp-it-acc.portal101.cn/deviceprofile/v4

3.2 device_id生成流程

1. 生成UUID v4 (uid)
       │
2. 计算priId = md5(uid)[:16]  ────→ 作为AES密钥
       │
3. RSA加密uid (PKCS#1 v1.5)   ────→ ep字段
       │
4. 收集23项浏览器指纹数据
       │
5. DES-ECB逐字段加密+字段名混淆
       │
6. 计算tn = md5(sorted key=value) ──→ 完整性校验
       │
7. JSON → Gzip压缩
       │
8. AES-CBC加密 (priId + IV="0102030405060708" + ZeroPadding)
       │
9. POST到数美API
       │
10. 解析响应 code=1100 → detail.deviceId
       │
11. getDeviceId() = "B" + deviceId

3.3 关键配置参数

参数 说明
RSA公钥 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDetfEgYD4aE1ZjmWJ6/jnPurhzI+yeRoJHWrnNtQMte3stQ4VjG3yu21FuN75E6cDpA9KtDXwcB2M/FiGUAe3G0rNotbWI8+SjZfUbW/OILFTzY0uaeEkmVGW5WyJ6weQbbr1xTCPa2OO3YIMeZljWUYHG5h21WAm/PATg8im8cQIDAQAB 用于加密uid
organization P9usCUBauxft8eAmUXaZ 设备标识归属
appId default 应用ID
apiHost fp-it-acc.portal101.cn 数美API域名

3.4 指纹数据收集(23项)

字段 来源 说明
ua navigator.userAgent 浏览器UA
platform navigator.platform Win32
canvas canvas 2D绘图 绘制'http://www.ishumei.com'文字取哈希
timezone Date.getTimezoneOffset() 时区偏移
res screen.width/height/colorDepth/devicePixelRatio 屏幕信息
plugins navigator.plugins 浏览器插件列表
referer document.referrer 来源页面
url location.href 当前URL
clientSize screenLeft/screenTop/body尺寸 窗口大小
vpw UUID v4 随机值
svm 时间戳 当前时间
trees UUID v4 随机值
pmf 时间戳 当前时间
cpucount navigator.hardwareConcurrency CPU核心数
battery navigator.getBattery() 电池状态
connectionRtt navigator.connection.rtt 网络延迟
maxTouchPoints navigator.maxTouchPoints 触控点数
status Flash检测+webdriver检测 环境检测
rtype 固定值"1" 类型标识
sdkver "3.0.0" SDK版本
subVersion "1.0.0" 子版本
appId "default" 应用ID
organization 配置值 组织标识

3.5 DES字段混淆

每个指纹字段使用独立的8字节DES密钥进行ECB模式加密,然后Base64编码,最后字段名映射为混淆名称。

混淆映射表(部分)

原字段 DES密钥 混淆名
appId q8zb1bs1 vw
organization ht432iov tj
os i7g8jtql vh
ua z5jc9qyp wr
canvas qy1d6fmu mi
plugins j916a142 vc
referer rf149ntc hv
res rbtd2cl6 pi
timezone 3w9lg8pr oi
svm mqcala0h nu
trees al8x9zt7 hc
vpw xzvnu5jt st
protocol (不加密) protocol

3.6 加密算法详解

RSA加密(uid → ep)

  • 使用JSEncrypt库
  • PKCS#1 v1.5填充
  • 输出为Base64字符串

DES-ECB加密(字段混淆)

  • 每个字段独立使用8字节密钥
  • ECB模式,逐块加密
  • 输出Base64编码

AES-CBC加密(数据体)

  • 密钥:priId(md5(uid)[:16],UTF-8编码)
  • IV:0102030405060708
  • 模式:CBC
  • 填充:ZeroPadding
  • 输入:gzip压缩后的JSON
  • 输出:hex字符串

完整性校验(tn字段)

tn = md5(sorted_key_value_string(data))

对所有key排序后拼接key+value为字符串,取MD5。

3.7 API请求格式

请求

POST https://fp-it-acc.portal101.cn/deviceprofile/v4

{
    "appId": "default",
    "organization": "P9usCUBauxft8eAmUXaZ",
    "ep": "RSA加密的uid(hex)",
    "data": "AES加密后的hex字符串",
    "os": "web",
    "encode": 5,
    "compress": 2
}

成功响应

{
    "code": 1100,
    "detail": {
        "deviceId": "XkNeGKe7f4Y5FtZamaxQPqL3ypegujSyds5eQGup13ajuer9XhBAM82w1QWifIm6KUNv2hu3tUTMwoXrVzD0ZA=="
    }
}

最终返回的device_id为:"B" + deviceId

3.8 Go实现要点

  1. 不需要浏览器:device_id由数美服务器生成,客户端只负责发送指纹数据和接收结果
  2. 指纹数据可伪造:服务端不校验指纹真实性,只需要格式正确
  3. 关键依赖:crypto/des、crypto/aes、crypto/rsa、crypto/md5、compress/gzip
  4. DES-ECB:Go标准库不提供ECB模式,需手动逐块实现
  5. AES ZeroPadding:标准库只提供PKCS7,需手动补零

四、HIF头部轮询机制

4.1 概述

Web端每个请求需要携带两个特殊头部:

  • x-hif-dliq
  • x-hif-leim

这两个值通过轮询DeepSeek的两个端点动态获取。

4.2 端点

类型 URL 对应头部
dliq https://hif-dliq.deepseek.com/query x-hif-dliq
leim https://hif-leim.deepseek.com/query x-hif-leim

4.3 响应格式

{
    "code": 0,
    "data": {
        "biz_code": 0,
        "biz_data": {
            "value": "9lspMrX9S0NlRuD7+ChfCz3ENqJPjH4qnMfnlPAwq0wfRuH2nmSepbg=.xuVOOVjUztQikXFf"
        }
    }
}

响应头 x-hif-ttl 包含缓存有效期(秒),默认600秒。

4.4 轮询策略

初始化 → 启动两个goroutine轮询
         │
         ├── 成功 → 缓存value → 等待TTL秒 → 继续轮询
         │
         └── 失败 → 指数退避(1s→2s→4s→...→max 600s) → 重试
  • 初始重试间隔:1秒
  • 退避倍数:2x
  • 最大间隔:600秒
  • 成功间隔:TTL(从响应头获取)

4.5 Go实现

internal/deepseek/hif/hif.go 实现了完整的轮询逻辑:

type HIFPoller struct {
    mu       sync.RWMutex
    dliq     string
    leim     string
    stopCh   chan struct{}
    client   *trans.Client     // 使用Chrome TLS
    fallback *http.Client      // 标准HTTP fallback
}

func (p *HIFPoller) Start()    // 启动两个轮询goroutine
func (p *HIFPoller) Stop()     // 停止轮询
func (p *HIFPoller) GetHeaders() map[string]string  // 获取当前HIF头部

五、TLS指纹对比

Android端

ClientHello: HelloSafari_Auto
ALPN: 强制 http/1.1 (forceHTTP11ALPN)

Web端

ClientHello: HelloChrome_Auto
ALPN: 自然协商 (支持 h2 和 http/1.1)
ForceAttemptHTTP2: true

实现位于 internal/deepseek/transport/transport.go

func TLSDialerForPlatform(platform string) func(...) {
    if platform == "web" {
        return chromeTLSDialer(dialContext)  // Chrome + HTTP/2
    }
    return safariTLSDialer(dialContext)      // Safari + HTTP/1.1
}

六、使用方式

6.1 设置面板切换

访问 WebUI 设置页面,在"接口平台"选项中选择:

  • Android端(默认):使用Safari TLS指纹,device_id为固定值
  • Web端(Chrome浏览器):使用Chrome TLS指纹+HTTP/2,动态生成数美device_id,轮询HIF头部

切换后立即生效,无需重启服务。

6.2 环境变量

# 也可通过环境变量设置默认平台
DS2API_PLATFORM_MODE=web

6.3 API设置

curl -X PUT http://localhost:5001/admin/settings \
  -H "Authorization: Bearer admin" \
  -H "Content-Type: application/json" \
  -d '{"platform":{"mode":"web"}}'

七、兼容性说明

  • 默认行为不变:未设置platform时默认为"android"
  • 向后兼容:所有现有配置和API保持不变
  • 热切换:切换平台时自动重建HTTP客户端、更新headers、启停HIF轮询
  • 代理兼容:使用代理时同样应用正确的TLS指纹和headers

八、测试状态

✅ go build ./...          编译通过
✅ go vet (核心包)         静态检查通过
✅ go test deepseek/...    deepseek包测试通过
✅ go test shumei/...      数美包测试通过
✅ npm run build webui     前端构建通过

注意:TestGetSettingsIncludesCurrentInputFileDefaults 是预先存在的测试失败,与本次改动无关。