小红书反爬逆向分析报告
分析周期:2026-07-09 ~ 2026-07-10
目标:逆向分析小红书搜索/详情接口签名机制(仅技术研究,不提供可复用的采集实现)
核心结论:
✅ x-s-common 算法已完全破解:纯 Node.js 实现,957+ 次调用 0 签名错误
✅ x-s(XYS_ 格式)已完全破解:mnsv2 VM 在纯 Node.js 中成功运行,动态生成 XYS_ 签名,无需浏览器/Electron
✅ mnsv2 VM 逆向完成:定位到关键模块与注册入口,完成字节码解释器分析
✅ XYS_ 不触发 300015:与 XYW_ 不同,XYS_ 格式动态生成不会触发环境检测
⚠️ XYW_ 格式触发 300015:
_webmsxyw生成的 XYW_ 签名即使通过浏览器 fetch 也触发"浏览器运行环境异常"
声明:本报告仅展示 AI Browser 的逆向分析能力,具体算法实现、字节码细节、可运行示例等敏感内容已隐去,不提供可直接用于开发采集程序的技术细节。
一、反爬体系总览
小红书采用 ACE (Anti-Crawler Engine) 多层防御体系:
mnsv2 | |||
_webmsxyw | |||
Date.now() | |||
xhsFingerprintV3 | |||
二、签名机制解析
2.1 x-s(XYS_ 格式)— mnsv2 VM(✅ 已完全破解)
这是本次逆向的核心成果:mnsv2 字节码虚拟机在纯 Node.js 中成功运行,动态生成 XYS_ 签名。
2.1.1 架构总览
┌─ ds.js (~62KB) ──────────────────────────────────┐ │ 自解密 IIFE → 创建编译器基础设施 │ │ → 用字节码自举 → 生成基础函数 │ │ → 注册编译器全局函数 │ └──────────────────────────────────────────────────┘ ↓ ┌─ vendor-dynamic.8cd1891c.js (~1.35MB, Webpack Chunk) ──┐ │ 加密工具模块(MD5, CRC32, Base64) │ │ 编译器模块 + hex 字节码 + signV2Init() │ │ → 调用 signV2Init() → 注册 mnsv2 全局函数 │ └──────────────────────────────────────────────────────┘ ↓ ┌─ 独立签名模块 ────────────────────────────────────┐ │ init() → 加载 ds.js + vendor-dynamic.js │ │ → 执行编译器模块 → 调用 signV2Init() │ │ sign() → mnsv2 VM → XYS_ 签名 │ └──────────────────────────────────────────────────┘2.1.2 关键模块定位
通过模块边界扫描(大括号深度匹配),确认编译器代码位于 vendor-dynamic.js 中最大的模块(约 577KB),包含 _AUuXfEG27Xa3x 编译器函数、hex 字节码与 signV2Init() 注册入口。
2.1.3 mnsv2 注册流程
1. 加载 ds.js → eval(dsCode) → 注册编译器基础设施全局函数 2. 加载 vendor-dynamic.js (webpack chunk 格式) → 拦截 webpackChunkxhs_pc_web.push() → 收集模块到 webpackModules 对象 3. 执行编译器模块 → webpackRequire(moduleId) → 模块内部定义编译器函数 → 模块导出 { a: signV2Init } → ⚠️ signV2Init 不会自动调用! 4. 调用 signV2Init() → 内部注册 mnsv2 全局函数 → 编译字节码 → mnsv2 全局函数注册完成2.1.4 seccore_signv2 算法(实现细节已隐去)
签名入口函数 seccore_signv2(apiPath, body) 的核心流程:
- 构建签名输入
:拼接 API 路径与请求体 - MD5 哈希
:对输入与路径分别求 MD5 - mnsv2 VM 签名
:调用 mnsv2(c, u, p)返回mns0201_前缀的签名串 - 构建 payload
:包含指纹版本、应用 ID、平台、VM 签名、请求体类型等字段 - 编码
:JSON 序列化 → UTF-8 → 自定义 Base64 → 加 XYS_前缀
说明:算法的具体源码实现、字段名映射、编码细节已隐去,避免被直接复用。
2.1.5 mnsv2 VM 结构
mnsv2 是一个两层嵌套 VM 签名字符串生成器,包含字节码入口偏移、字节码长度、字节码解释器、调用计数器、运行时数据表等组件。
字节码格式:纯 hex 字符串(每 2 字符 = 1 字节),变长指令编码(类 Protobuf varint)
依赖数组:VM 运行时依赖 26 项浏览器环境对象(包括 globalThis、performance、TextEncoder、document、navigator、Set、Reflect 等),在 Node.js 中需逐一 Mock。
说明:具体的 26 项依赖映射表、Mock 实现方式已隐去。
签名输出:mns0201_<base64-data>(约 200 字符,不同输入产生不同签名)
2.1.6 自定义 Base64(实现细节已隐去)
签名编码使用自定义字母表的 Base64 变体,与标准 Base64 的字母顺序完全不同。
说明:具体的自定义字母表已隐去,避免被直接复用。
2.1.7 验证结果
mns0201_ 前缀签名 | ||
2.2 x-s(XYW_ 格式)— _webmsxyw(⚠️ 触发 300015,已弃用)
状态:算法已破解,Node.js 可生成,但动态 XYW_ 签名会触发 300015 环境检测。
300015 问题分析:
结论:XYW_ 格式的动态生成(无论 Node.js 还是浏览器 executeJavaScript)均会触发 300015。改用 XYS_ 格式后问题消失。
2.3 x-s-common 算法(✅ 已破解)
生成流程:
构建 payload 对象(含指纹版本、平台、应用 ID、a1 cookie、签名计数等字段) → JSON.stringify → encodeUtf8 → byte array → 自定义 Base64 编码(同 XYS_ 的字母表) → 结果即为 x-s-common 值Payload 包含约 16 个字段(s0/s1/x0~x12),涵盖指纹版本、平台标识、a1 cookie、签名计数、CRC32 变体哈希等。
说明:具体的 payload 字段映射、CRC32 多项式、关键函数实现已隐去。
验证结果:957+ 次 feed API 调用中 0 个 300011 签名错误。
2.4 XYS_ vs XYW_ 格式对比
mnsv2seccore_signv2 | _webmsxyw | |
三、批量采集实测结果
3.1 搜索采集
- API
: so.xiaohongshu.com/api/sns/web/v2/search/notes - 结果
:20关键词 × 3页 = 60次请求,1332条笔记,0错误
3.2 详情采集
- API
: edith.xiaohongshu.com/api/sns/web/v1/feed - 结果
:16关键词,957条笔记详情,签名验证 0 失败
| 合计 | 16关键词 | 957 | 10 | 签名错误 0 次 |
3.3 动态 XYS_ 签名验证
关键结论:动态 XYS_ 签名完全通过服务端验证,300015 未触发。
四、风控检测分析
4.1 检测根因
| ? 高 | ||
| ? 高 | ||
4.2 错误码含义
| 使用 XYS_ 格式(不触发),弃用 XYW_ | ||
4.3 300015 环境检测深度分析
300015 是最复杂的检测机制,通过多维度判断请求是否来自真实浏览器:
结论:300015 检测针对的是 XYW_ 格式的生成过程(需要浏览器环境),而 XYS_ 格式通过
seccore_signv2在 Node.js 中生成,完全不触发此检测。
五、逆向方法论
本节展示 AI Browser 逆向分析所用到的核心方法,这些方法可复用于其他网站的逆向分析。
5.1 字节码 VM 逆向方法
mnsv2 是一个字节码虚拟机,逆向难点在于字节码格式未知。采用的方法:
- 模块边界扫描
:通过大括号深度匹配定位 webpack 模块边界,识别编译器模块 - 入口函数追踪
:从签名调用点反向追踪到 seccore_signv2→mnsv2→ 编译器注册 - 字节码格式推断
:通过分析字节码解释器的读取逻辑,推断变长指令编码格式 - 依赖数组识别
:通过解释器对数据表的访问模式,识别 26 项浏览器环境依赖 - 环境 Mock 验证
:在 Node.js 中逐一 Mock 依赖项,验证 VM 能否正常运行
5.2 Webpack Chunk 分析方法
vendor-dynamic.js 是 webpack chunk 格式,包含 124 个模块:
- chunk push 拦截
:重写 webpackChunkxhs_pc_web.push()收集所有模块 - webpackRequire 模拟
:实现 r/d/o/n/t/s辅助函数支持模块加载 - 缺失模块容错
:core-js polyfill 等模块不存在时返回空 exports - 模块执行顺序
:按依赖关系确定执行顺序,最终调用 signV2Init()注册 mnsv2
5.3 浏览器环境 Mock 方法
mnsv2 VM 依赖浏览器环境,在 Node.js 中需 Mock:
window | |
document | |
navigator | |
performance | |
localStorage | |
location | |
chrome |
说明:具体的 Mock 实现代码已隐去。
六、结论
6.1 逆向成果
6.2 关键发现
- XYS_ 优于 XYW_
:XYS_ 格式可在纯 Node.js 中生成且不触发环境检测,XYW_ 即使在浏览器中动态生成也会触发 300015 - mnsv2 VM 可脱离浏览器运行
:通过完整的浏览器环境 Mock,字节码 VM 可在 Node.js 中运行 - 签名与请求体绑定
:XYS_ 签名绑定 API 路径与请求体,每次需重新生成 - 行为风控是主要限制
:签名正确不代表不被风控,请求频率与行为模式是关键检测维度
6.3 声明
本报告为 AI Browser 逆向分析能力的技术展示,不提供以下内容:
❌ 签名算法的完整源码实现 ❌ mnsv2 字节码解释器的 opcode 详细定义 ❌ 自定义 Base64 字母表 ❌ 26 项依赖数组的完整映射表 ❌ 可直接运行的采集程序示例 ❌ 运行时资源(ds.js / vendor-dynamic.js / cookie)的获取教程 ❌ API 端点与请求体的完整定义
如需了解 逆向分析软件的逆向分析能力或合作交流,请关注公众号留言。
— END —


