☰
抖音 Web 端 a_bogus、X-Bogus 算法拆解:从浏览器参数到请求签名
2026/9/29 21:54:19 网站建设 项目流程

抖音 Web 端 a_bogus、X-Bogus 算法拆解:从浏览器参数到请求签名

摘要:本文基于本地web目录的四个文件,专门拆解抖音 Web 端a_bogus、X-Bogus的参数链路、浏览器环境、JavaScript 签名器和 Python 请求编排。文章只保留结构性信息,真实 Cookie、msToken、verifyFp、webid和完整签名统一脱敏。

关键词:抖音 a_bogus、X-Bogus、六神算法、detail.py、浏览器指纹、请求签名、SM3、RC4、Web 协议分析

文章目录

  • 抖音 Web 端 a_bogus、X-Bogus 算法拆解:从浏览器参数到请求签名
    • 先说结论:Web 侧不是 Android 七神的同一套代码
    • 一、目录里的文件分别做什么?
    • 二、`detail.py` 的请求链路
    • 三、`19ab.js` 的 a_bogus 高层流程
      • 1. 对输入做固定后缀处理
      • 2. 做双重摘要
      • 3. 把 UA 与浏览器环境混入字节数组
      • 4. 随机掩码、重排与校验
      • 5. 使用自定义 64 字符表编码
    • 四、pure / 164 两份实现怎么对照?
      • `a_bogus_pure.js`
      • `a_bogus164.js`
    • 五、浏览器参数为什么比 aweme_id 更容易出问题?
    • 六、最容易踩的坑
      • 1. 把“六神”当作官方固定名称
      • 2. 把硬编码 Cookie 当成长期方案
      • 3. 只看签名长度
      • 4. 忽略随机与时间
      • 5. 把 pure.js 当成标准实现
      • 6. 只看 HTTP 200
      • 7. 忽略 JavaScript 运行时差异
    • 七、建议的脱敏调试基线
    • 结语:真正难的是把浏览器上下文对齐

先说结论:Web 侧不是 Android 七神的同一套代码

“六神”是社区常用称呼,不是抖音官方算法名。当前web目录能直接观察到的重点,是三条 Web 签名实现线:

  • 19ab.js:导出式调用getABogus,由detail.py通过 ExecJS 调用;
  • a_bogus_pure.js:可读的DualBogusSigner,同时提供sign_a_bogus和sign_x_bogus;
  • a_bogus164.js:另一份同类长签名实现,入口是generate_a_bogus。

所以本文讨论的是Web 侧的 a_bogus / X-Bogus 请求签名链路,不把它和 Android 目录里的 X-Gorgon、X-Khronos、X-Medusa 等字段混成一套,更不把本地脚本描述成官方、永久有效或已完成线上验签的实现。

图 1:从浏览器输入到 a_bogus 生成,再到接口响应的高层流程。

一、目录里的文件分别做什么?

文件角色代码中能确认的行为
detail.py业务请求编排构造 Query、调用 ExecJS、追加a_bogus、发起 detail GET
19ab.js长签名入口getABogus混入参数、data、UA、时间和随机字段,再做自定义编码
a_bogus_pure.js可读对照实现DualBogusSigner同时提供短签名和长签名接口
a_bogus164.js同类历史实现generate_rc4_bb_str→generate_random_str→generate_a_bogus

图 2:业务入口、浏览器上下文、参数调度和 signer 的职责边界。

二、detail.py的请求链路

detail.py的核心流程可以压缩成六步:

  1. 准备device_platform、aid、channel、aweme_id等业务参数;
  2. 补齐浏览器语言、平台、屏幕、CPU、内存、网络和版本字段;
  3. 放入webid、msToken、verifyFp、fp等动态上下文;
  4. 用urllib.parse.urlencode序列化 Query;
  5. 调用19ab.js的getABogus(query, data, userAgent);
  6. 把返回值追加到params['a_bogus'],再请求/aweme/v1/web/aweme/detail/。

对应的脱敏伪代码如下,值全部是占位符:

params={"device_platform":"webapp","aid":"<AID>","channel":"<CHANNEL>","aweme_id":"<AWEME_ID>","browser_name":"<BROWSER>","browser_version":"<VERSION>","screen_width":"<WIDTH>","screen_height":"<HEIGHT>","webid":"<WEBID>","msToken":"<MS_TOKEN>","verifyFp":"<VERIFY_FP>","fp":"<VERIFY_FP>",}query=urllib.parse.urlencode(params)a_bogus=js.call("getABogus",query,"",USER_AGENT)params["a_bogus"]=a_bogus response=requests.get("https://www.douyin.com/aweme/v1/web/aweme/detail/",params=params,headers=REDACTED_HEADERS,)

这里有两个工程重点:先固定 Query,再签名,最后追加a_bogus;签名后不要再偷偷改变参数顺序、编码或 UA。当前源码把空 Body 传成None,而 JavaScript 中又执行data += 'dhzx',在 JavaScript 语义下可能把null转成字符串的一部分。这是一个值得单独验证的实现细节,不能直接当成服务端协议结论。

三、19ab.js的 a_bogus 高层流程

19ab.js的getABogus不是简单的 MD5 拼接,大致可拆成下面几层:

1. 对输入做固定后缀处理

代码会把 Query 和 data 分别拼接固定后缀,再进入后续处理。源码中能看到dhzx字样;这类固定后缀属于实现输入的一部分,版本变化后可能改变。

2. 做双重摘要

get_arr内部实现了 SM3 风格的压缩流程,get_arr29会分别处理参数串和 data,并取摘要中的部分字节参与后续字段组装。文章只解释数据流,不展开常量表和可复用签名材料。

3. 把 UA 与浏览器环境混入字节数组

UA 会经过数组置换、异或和自定义编码;同时,时间戳、两次时间的微小差值、UA 长度、窗口环境、AID、pageId等字段会进入中间数组。也就是说,同一组 Query 换一个 UA、窗口尺寸或时间,输出就可能变化。

4. 随机掩码、重排与校验

代码使用随机字节生成掩码,对数组进行重排并计算异或校验,再把结果拼成字符串。随机性意味着同一输入不一定得到同一串文本,调试时应比较字段长度、字符集和中间阶段,而不是硬编码最终值。

5. 使用自定义 64 字符表编码

最终结果使用定制字符表做 Base64-like 编码,形成约 160 字符左右的a_bogus字符串。当前目录的不同实现和历史样例长度并不完全一致,不能用“长度正确”代替线上兼容性验证。

四、pure / 164 两份实现怎么对照?

a_bogus_pure.js

DualBogusSigner暴露两条入口:

  • sign_a_bogus(query, userAgent):处理 Query、固定后缀、UA、时间字段和窗口环境,再做 RC4 与s4表编码;
  • sign_x_bogus(query, body):对 Query/Body 做双重摘要,组装短载荷、随机 key 和校验字节,再用 RC4 与s2表编码。

这份文件适合阅读模块边界,但审计发现其中的 SM3 压缩实现和标准 SM3 有差异,且字段装配与a_bogus164.js并非完全等价。因此它更适合作为实验性对照实现,不能直接宣称是真实服务端算法。

a_bogus164.js

这份代码把流程拆成generate_rc4_bb_str、generate_random_str和generate_a_bogus。它同样会混入 Query、UA、窗口环境、时间、AID、pageId和随机字段,再经过 RC4 与自定义 64 表编码。文件末尾带有历史测试调用,版本字段、UA 和示例环境互相并不完全一致,这也是版本漂移的直接证据。

五、浏览器参数为什么比 aweme_id 更容易出问题?

Web 请求通常可以分成四层:

  1. 业务层:aweme_id、接口路径、分页或场景字段;
  2. 版本层:device_platform、aid、channel、version_code、version_name;
  3. 能力层:屏幕尺寸、CPU 核数、内存、网络类型、浏览器和渲染引擎字段;
  4. 身份层:webid、msToken、verifyFp/fp、Cookie 和 referer。

这些字段不是越多越好,而是要互相一致。例如:

  • UA 声称 Chrome 版本与browser_version不匹配;
  • Windows 平台与移动端字段混用;
  • Query 编码前后发生二次转义;
  • 签名前使用一个 UA,发请求时又换了另一个 UA;
  • Cookie、msToken、verifyFp已过期,却只重新生成a_bogus。

当前目录还存在历史快照之间的环境不一致:detail.py的屏幕/UA 参数、19ab.js内部环境字符串,以及pure/164里的固定窗口字段并不完全相同。它们应视为不同版本或实验样例,不能拼接成一套“标准环境”。

图 3:字段名和职责可以展示,真实 Cookie、Token、webid 和完整签名不要公开。

六、最容易踩的坑

1. 把“六神”当作官方固定名称

当前目录的代码围绕a_bogus/X-Bogus,而不是 Android 七神容器。文章、标题和对外宣传应明确 Web 侧视角。

2. 把硬编码 Cookie 当成长期方案

detail.py内有完整样式的 Cookie、msToken、verifyFp和webid。它们可能过期、失效或属于特定会话,不能原样复制到博客、日志、截图或示例代码。

3. 只看签名长度

本地函数能返回 16 字符或约 160 字符,只能说明输出走通。没有官方 golden vector、服务端对照和目标版本样本时,不能把长度、字符集或 Base64 外观当作线上验签。

4. 忽略随机与时间

a_bogus过程混入Date.now()和随机字段;重复运行出现不同结果是预期现象。回归测试应固定输入、记录时间窗口,并比较中间摘要与结构。

5. 把 pure.js 当成标准实现

当前 pure 版本与标准 SM3、a_bogus164.js的字段装配存在差异。它适合做阅读和模块拆分,不适合直接宣传成现网通杀方案。

6. 只看 HTTP 200

需要同时记录 HTTP 状态、业务 JSON、响应体大小、错误字段和分页状态。请求成功返回 200,不代表业务层已经接受全部上下文。

7. 忽略 JavaScript 运行时差异

19ab.js和a_bogus164.js存在隐式全局变量、加载即执行测试输出等写法;放进严格模式、CommonJS 或长期驻留进程后,可能出现状态污染、重复初始化或ReferenceError。部署前应把函数封装进明确模块,隔离随机状态,并为目标 Node/ExecJS 运行时单独做回归。

七、建议的脱敏调试基线

推荐“一条请求、一个 UA、一个固定 Query、一个占位会话”开始:

  1. 记录参数名、编码后 Query 的长度和摘要;
  2. 用<WEBID>、<MS_TOKEN>、<VERIFY_FP>、<COOKIE_REDACTED>替换敏感值;
  3. 记录a_bogus/X-Bogus的长度、字符集和生成耗时;
  4. 对比签名前 Query 与最终 URL,确认只新增预期字段;
  5. 记录 UA、屏幕、平台和版本字段是否一致;
  6. 把服务端响应和版本信息加入 golden case;
  7. 不把本地格式检查写成“永久线上可用”。

本地脱敏检查可以验证:sign_a_bogus输出约 159 字符、sign_x_bogus输出 16 字符,字符集落在自定义 Base64 范围内;这只是结构性结果,不代表服务端验签通过。

结语:真正难的是把浏览器上下文对齐

真正影响稳定性的,是 Query 顺序、URL 编码、UA、窗口环境、时间随机性、动态会话和接口版本能否处在同一条请求链上。

本文只对本地web目录做结构化阅读,不公开任何可复用凭据,也不把实验性实现包装成官方算法。

说明:版本、页面脚本和服务端策略会变化。本文用于协议阅读、兼容性测试和工程排错;真实 Cookie、Token、webid、verifyFp 与完整签名值均不应公开。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询