JS逆向实战:拆解有道翻译身份校验漏洞,实现风控绕过
寄语:本文为纯技术逆向思路分享,该漏洞目前已提交至网易src,思路仅供交流学习,严禁用于非法爬虫、批量调用等违规用途,任何不当使用后果由使用者自行承担。
适用场景:前端JS逆向、接口签名分析、Web风控逻辑审计、漏洞原理学习
核心结论前置:有道翻译网页版AI翻译接口的核心风控依赖 yduuid、token、sign 三重参数校验,但后端对 yduuid 设备指纹校验存在逻辑缺陷,支持随机伪造值生效,可直接绕过翻译次数、调用频次限制,实现无限制调用AI翻译接口。
概述
在有道翻译的 Web 端,用户每次翻译请求都需要携带 sign、token 和 yduuid 三个加密参数,平台通过这些参数实现身份标识和请求校验,从而限制翻译调用次数。然而在实际测试中发现,后端对 yduuid 的身份校验存在缺陷,导致风控机制可被绕过。
本文将从侦察定位开始,逐步讲解三个关键参数的逆向分析思路:sign 的加密算法追踪、yduuid 的生成机制溯源、翻译接口 sign 的构造方式,以及最终的风控绕过验证过程。每一步都附带实际调试截图,力求完整还原分析链路。
一、侦察阶段:锁定关键加密参数
逆向分析的第一步永远是侦察。打开有道翻译主页后,我们首先关注页面加载时浏览器与服务器之间的数据交互。通过浏览器的开发者工具(F12),在 Network 面板中捕获首页请求,发现服务器下发的数据包中包含三个加密参数:sign、token 和 yduuid。

图 1:有道翻译主页,三个加密参数 sign、token、yduuid 可见
在开发者工具中进一步查看首页数据包的详情,确认这三个参数均出现在请求中。其中 sign 和 yduuid 由前端生成,token 则需要关注服务器是否在响应中提供。

图 2:F12 开发者工具中捕获的首页数据包,3 个加密参数清晰可见
查看响应内容后,关键信息浮现:服务器在响应中直接返回了 token 值,同时还包含一个名为 secretKey 的字段。这个 secretKey 在后续翻译接口的 sign 构造中将扮演核心角色,暂时记下这个值。

图 3:首页响应中包含服务器下发的 token 和 secretKey
二、sign 参数逆向:从混淆代码到加密算法
确认了三个关键参数后,下一步是逆向 sign 的生成逻辑。思路是:sign 是请求参数,必然在前端代码中某处被构造和赋值。通过路由分析,在 JS 源码中成功定位到 sign 的加密入口。

图 4:通过路由定位到 sign 的加密方法
定位到的代码经过了混淆处理,原始形态为 (0, i.Jt)(`${P}/translate_llm/secret`, (0, n.A)((0, n.A)({},e), C(t, o)))。解混淆后还原为可读形式:
i.Jt(`${P}/translate_llm/secret`, n.A(n.A({}, e), C(t, o)))
这里 n.A() 函数的作用是将第二个参数合并到第一个参数对象中,类似于 Object.assign。核心在于 C(t, o) 这个调用——它就是 sign 构造的关键函数。

图 5:解混淆后的代码,n.A() 合并对象,C(t, o) 构造 sign
进入 C 函数内部,发现 sign 的构造逻辑:sign 由当前时间戳和一段固定字符串作为参数传入函数后计算得出。这说明 sign 的值仅与时间相关,不携带用户身份信息。

图 6:进入 C 函数,sign 由时间戳和固定字符串构造
进一步分析 C 函数的实现,确认 sign 的完整构造公式为:将 client、mysticTime、product、key 四个字段按固定格式拼接后,对拼接结果进行 MD5 加密。
sign = md5(`client=${g}&mysticTime=${e}&product=${h}&key=${t}`)

图 7:sign 的完整构造公式,仅与时间戳有关

图 8:sign 构造细节确认
至此,sign 参数的逆向分析完成。其核心特点是:sign 的值完全由时间戳驱动,不绑定用户身份,因此在同一时间窗口内可以被复用。
三、yduuid 追踪:浏览器指纹与 MurmurHash3
接下来分析 yduuid 参数。yduuid 看起来是用户身份标识,追踪它的生成来源是理解整个风控机制的关键。通过在代码中设置断点,逐步追踪 yduuid 的赋值路径。

图 9:通过断点分析追踪 yduuid 的来源
在断点处发现 yduuid 的读取来自 localStorage。代码 localStorage.getItem("yduuid") 从浏览器本地存储中取出该值。这意味着 yduuid 在某个时间点被写入了 localStorage,我们需要找到写入的位置。

图 10:yduuid 来自 localStorage.getItem,全局搜索 setItem 定位写入点
在代码中全局搜索 setItem("yduuid,找到写入逻辑。分析后发现 yduuid 实际上就是对象 t 的 visitorId 属性值。

图 11:yduuid 等于 t.visitorId
继续深入,进入设置 visitorId 的函数内部,追踪 visitorId 本身是如何生成的。

图 12:进入 set visitorId 的函数

图 13:visitorId 生成逻辑的进一步分析
最终发现,visitorId 是通过采集浏览器指纹和设备参数,将各项数据拼接后传入 w 函数,由 MurmurHash3 算法计算得到一个 32 位哈希值。这就是 yduuid 的完整生成链路:浏览器指纹与设备参数拼接后经 MurmurHash3 哈希。

图 14:visitorId 由浏览器指纹和设备参数拼接后经 MurmurHash3 加密生成
四、翻译接口的 sign 构造
前面分析的 sign 是首页请求使用的,而实际翻译功能有自己的数据包和 sign 构造方式。定位到翻译功能的数据包后,发现它同样依赖 sign、token 和 yduuid 三个参数,但 token 和 yduuid 的值在会话期间保持不变,只有 sign 随每次翻译请求重新生成。

图 15:翻译功能数据包,依旧依赖 3 个加密参数,但 token 和 yduuid 不变
翻译接口的 sign 需要单独分析其加密方式。通过翻译数据包的路由定位,找到 sign 在翻译请求中的构造代码。

图 16:通过翻译数据包路由定位 sign 的加密方式
在定位到的位置设置断点,进行动态调试,尝试捕获 sign 的实际生成过程。

图 17:断点分析翻译接口的 sign 生成
初次断点并未直接捕获到 sign 的值,需要继续向下追踪调用链,查看 sign 在何处被最终赋值。

图 18:未找到 sign 值,继续深入调用链
在更深的调用中,定位到 sign 的赋值点:sign 的值等于变量 v,而 v 由 o(m, t) 函数计算得到。其中参数 m 是翻译请求的载荷(payload),t 是一段固定字符串。

图 19:sign = v,由 o(m, t) 赋值,m 为载荷,t 为固定字符串
进入函数 o 内部,分析其返回值结构。函数 o 返回一个数组,数组的第一个元素即为 sign 的来源。

图 20:进入函数 o 分析返回值结构
通过分析函数 o 的实现,其核心逻辑是:将翻译请求的载荷(payload)转换为一个对象,在对象上增加一个 key 属性并赋值为 "QGCmKoX7N7wACtICx3PSaWzoPJza2DSC"——这个值与首页响应中服务器返回的 secretKey 完全一致。随后将该对象的键值对拼接后进行 MD5 加密,得到最终的 sign。
sign = md5(拼接({ ...payload, key: "QGCmKoX7N7wACtICx3PSaWzoPJza2DSC" }))

图 21:函数 o 返回数组,首元素为载荷转对象后追加 secretKey 再 MD5
五、风控绕过验证
三个参数的生成逻辑已全部还原:sign 由时间戳或载荷加 secretKey 经 MD5 构造,token 由服务器下发,yduuid 由浏览器指纹经 MurmurHash3 生成。基于这些分析结果,用 Python 和 JavaScript 构造完整的翻译请求,模拟正常的参数签名流程。

图 22:构造 Python/JS 脚本成功发送请求,绕过翻译次数风控限制
请求发送成功,翻译次数限制被绕过。在此基础上进一步测试:如果将 yduuid 替换为一个随机值进行 MD5 加密构造,同样能够成功绕过风控。这意味着后端并未对 yduuid 的有效性进行校验。

图 23:随机 yduuid 经 MD5 构造后同样成功绕过风控
六、关键发现与总结
综合以上分析,可以得出结论:有道翻译平台后端对 yduuid 的身份校验存在异常。前端虽然通过浏览器指纹和设备参数精心构造 yduuid,但后端并不验证其真实性,任意随机值构造的 yduuid 均可被接受。

图 24:最终结论——后端对 yduuid 身份校验存在缺陷
从攻防视角来看,这个案例揭示了一个常见的安全设计误区:前端加密不等于后端安全。有道翻译在前端投入了大量工作来生成 sign、token 和 yduuid 三个参数,其中 sign 使用了 MD5 签名、yduuid 使用了 MurmurHash3 指纹哈希,技术上具有一定复杂度。但由于后端缺少对 yduuid 的有效性校验,整个风控体系的核心一环形同虚设。
对于防御方而言,正确的做法应包括:后端对 yduuid 进行服务端校验或生成,不信任前端传来的指纹值;对同一 IP 或会话的翻译频率进行独立计数;将 secretKey 等关键密钥从响应中移除,改由服务端内部持有。只有前后端协同验证,才能构建真正有效的风控体系。