小红书x-s参数加密逆向实战

// 实战案例:小红书x-s参数加密逆向实战

// 网址:https://www.xiaohongshu.com/explore

概述

小红书Web端在API请求中使用X-S签名机制进行请求验证,本笔记完整记录了该签名机制的逆向分析过程,包括环境模拟、算法还原和完整实现。

逆向网页分析

1752734634041-cf93099e-5339-441c-964d-d03698bcda3e.png1752734750599-d6e5fce2-3c0d-4a5e-9cc3-ca95f129c2c4.png

1752734864195-78c9f6e6-40b0-4235-81c0-8577d7985060.png

1752734961292-b9cc53d6-d834-4d80-82cc-f2068c1dcbd7.png

1752735038694-67cf87ba-e58a-4d52-af9e-333fd4c6ff2c.png

1752735076970-fbe39389-a6a6-4aa7-b0d7-3d5f5fc750ea.png

1752735212021-00235998-7a6b-4d70-81b8-356f366bc38c.png

1752735340405-5be98f70-b82f-408f-b91c-8ca1dffa7fc9.png

1752735547841-04e3283b-962f-401f-b3da-a18dfb153b91.png

1752736099951-685eada3-c9f9-4b05-b349-55e91e786a53.png

1752736313350-570982bb-8491-4082-bb74-d955040a8ec1.png

核心签名流程分析

1. 签名生成流程

  1. 构造请求参数JSON字符串
  2. 计算参数MD5值
  3. 使用mnsv2算法生成签名
  4. 构造X-S头部信息

2. 关键数据结构

s = {
    x0: "4.2.1",        // 版本号
    x1: "xhs-pc-web",   // 平台标识
    x2: "Windows",      // 操作系统
    x3: f,              // mnsv2算法生成的签名
    x4: 'object'        // 固定值
};

三、关键代码解析

1. 环境模拟实现

// 全局对象模拟
window = watch(global, "globalThis");
self = window;
globalThis = self;

// 浏览器环境模拟
Navigator = function() {};
Location = function() {};
Storage = function() {};
Screen = function() {};
HTMLHtmlElement = function() {};
HTMLBodyElement = function() {};
HTMLDocument = function() {};

2. 核心签名函数

function main() {
    // 1. 构造请求参数
    const params = {
        cursor_score: "",
        num: 31,
        refresh_type: 1,
        note_index: 10,
        // ...其他参数
    };
    
    // 2. 生成参数字符串
    const paramStr = `/api/sns/web/v1/homefeed${JSON.stringify(params)}`;
    
    // 3. 计算MD5
    const md5 = CryptoJS.MD5(paramStr).toString();
    
    // 4. 生成签名
    const signature = window.mnsv2(paramStr, md5);
    
    // 5. 构造X-S头部
    const x_s = "XYS_" + b64Encode(encodeUtf8(JSON.stringify({
        x0: "4.2.1",
        x1: "xhs-pc-web",
        x2: "Windows",
        x3: signature,
        x4: 'object'
    })));
    
    return {
        "X-s": x_s
    };
}

3. 辅助函数实现

// Base64编码函数
function b64Encode(e) {
    // ...实现细节
}

// UTF-8编码函数
function encodeUtf8(e) {
    // ...实现细节
}

// 三重编码转换函数
function tripletToBase64(e) {
    // ...实现细节
}

// 分块编码函数
function encodeChunk(e, a, r) {
    // ...实现细节
}

四、完整实现示例

1. 准备工作

// 安装依赖
const CryptoJS = require('crypto-js');

// 导入mnsv2算法实现
require('./mnsv2.js'); 

2. 签名生成示例

// 示例请求参数
const apiPath = '/api/sns/web/v1/homefeed';
const params = {
    cursor_score: "1.7524207749900007E9",
    num: 20,
    refresh_type: 1,
    category: "homefeed.food_v3",
    // ...其他参数
};

// 生成签名
function generateXSign(apiPath, params) {
    // 1. 构造参数字符串
    const paramStr = apiPath + JSON.stringify(params);
    
    // 2. 计算MD5
    const md5 = CryptoJS.MD5(paramStr).toString();
    
    // 3. 调用mnsv2算法
    const signature = window.mnsv2(paramStr, md5);
    
    // 4. 构造X-S头部
    const x_s = "XYS_" + b64Encode(encodeUtf8(JSON.stringify({
        x0: "4.2.1",
        x1: "xhs-pc-web",
        x2: "Windows",
        x3: signature,
        x4: 'object'
    })));
    
    return x_s;
}

// 使用示例
const xSign = generateXSign(apiPath, params);
console.log('生成的X-S签名:', xSign);

补环境代码

import requests
import subprocess
import json
import re

cookies = {
    'abRequestId': 'caed210b-2b2f-586e-a1b0-b6ee2c5086e7',
    'xsecappid': 'xhs-pc-web',
    'a1': '197e9c5585d7b1lzytcj54rjel35piyzlurwevylq50000252033',
    'webId': '2e9b5644ae5f2f038aadc5da4021d1a6',
    'gid': 'yjWdjS2Kif1DyjWdjS22Y7hv2fWDy1uv9SV2F1A4FVd1qE282U3vud888J2J8qq8q4WWYqi0',
    'web_session': '040069b588606840034dfab7593a4b94066c12',
    'webBuild': '4.72.0',
    'unread': '{%22ub%22:%22687338ef000000001d00f0ba%22%2C%22ue%22:%2268739fd9000000001703265f%22%2C%22uc%22:26}',
    'loadts': '1752423777445',
    'acw_tc': '0a4ad9b317524275626347245e7c600a016e1b6832a1b6feef86e40dfb6285',
    'websectiga': '59d3ef1e60c4aa37a7df3c23467bd46d7f1da0b1918cf335ee7f2e9e52ac04cf',
    'sec_poison_id': '2a1dd9b4-a73c-4ad7-8beb-fca89f464dec',
}

output = subprocess.run(['node', '小红书.js'], capture_output=True, encoding='utf-8', text=True).stdout
pattern = r"'X-s'\s*:\s*'([^']+)'"  # 匹配 'X-s': '任意内容'
match = re.search(pattern, output)


x_s_value = match.group(1)
print(x_s_value)


headers = {
    'accept': 'application/json, text/plain, */*',
    'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'cache-control': 'no-cache',
    'content-type': 'application/json;charset=UTF-8',
    'origin': 'https://www.xiaohongshu.com',
    'pragma': 'no-cache',
    'priority': 'u=1, i',
    'referer': 'https://www.xiaohongshu.com/',
    'sec-ch-ua': '"Not)A;Brand";v="8", "Chromium";v="138", "Microsoft Edge";v="138"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
    'sec-fetch-dest': 'empty',
    'sec-fetch-mode': 'cors',
    'sec-fetch-site': 'same-site',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0',
    'x-b3-traceid': 'df32220d5b5cc2a6',
    'x-s': x_s_value,
    'x-s-common': '2UQAPsHC+aIjqArjwjHjNsQhPsHCH0rjNsQhPaHCH0c1PjhlHjIj2eHjwjQgynEDJ74AHjIj2ePjwjQhyoPTqBPT49pjHjIj2ecjwjHFN0qUN0ZjNsQh+aHCH0rE+9LEGALMwepD+9HlJokE4B+x+/zUyfpVPApIygSCJopU49p92nll+/ZIPeZU+/HIPAPjNsQh+jHCHjHVHdW7H0ijHjIj2eWjwjQQPAYUaBzdq9k6qB4Q4fpA8b878FSet9RQzLlTcSiM8/+n4MYP8F8LagY/P9Ql4FpUzfpS2BcI8nT1GFbC/L88JdbFyrSiafp/8DMra7pFLDDAa7+8J7QgabmFz7Qjp0mcwp4fanD68p40+fp8qgzELLbILrDA+9p3JpH9LLI3+LSk+d+DJfpSL98lnLYl49IUqgcMc0mrcDShtMmozBD6qM8FyFSh8o+h4g4U+obFyLSi4nbQz/+SPFlnPrDApSzQcA4SPopFJeQmzBMA/o8Szb+NqM+c4ApQzg8Ayp8FaDRl4AYs4g4fLomD8pzBpFRQ2ezLanSM+Skc47Qc4gcMag8VGLlj87PAqgzhagYSqAbn4FYQy7pTanTQ2npx87+8NM4L89L78p+l4BL6ze4AzB+IygmS8Bp8qDzFaLP98Lzn4AQQzLEAL7bFJBEVL7pwyS8Fag868nTl4e+0n04ApfuF8FSbL7SQyrLUarQl4LShyBEl20YdanTQ8fRl49TQc7bgz9qAq9zV/9pnLoqAag8m8/mf89pDPBloanDMqA++y9GU4gzmanSNq9SD4fp3nDESpbmF+BEm/9pgLo4bag83Ggkm+fpfLo4G/BEmqM+l4FQQPMzUagYb+LlM474Yqgq3qfpkGdbU/9p8yf4Ay7bF8FS38Bp88AmS2b4j2rSi87+f/npA+fk0JrS3cnLALozLanSU8bbl4Fih4gcEa/P98/+c4b8QyLESPpmFJrSk+npfpd4maopF/L4l47YQPMbpaL+b8LkYLrboJsRAygbF/LSipdzQynpSngpFP9PEngc6c/mSyfkI+DS3zMmo4gzNJ7b7PFDA/9phqgzxLLIM8nS0cgPAqBY7anYmqA+s/7PA4gzAGS8F2DSh87+x4gzGagG9qAP7LURQP9zA+fiAqA+M478QyBpAPgbF80Ydt7zQyaV6anVIqAb0J9pn80pA8rG7qMSc47qjNsQhwaHC+0W7P0H7PeqVHdWlPsHCPsIj2erlH0ijJfRUJnbVHdF=',
    'x-t': '1752427578815',
    'x-xray-traceid': 'cc026962dad8fc3a0488d0d5ac4d1ac7',
    # 'cookie': 'abRequestId=caed210b-2b2f-586e-a1b0-b6ee2c5086e7; xsecappid=xhs-pc-web; a1=197e9c5585d7b1lzytcj54rjel35piyzlurwevylq50000252033; webId=2e9b5644ae5f2f038aadc5da4021d1a6; gid=yjWdjS2Kif1DyjWdjS22Y7hv2fWDy1uv9SV2F1A4FVd1qE282U3vud888J2J8qq8q4WWYqi0; web_session=040069b588606840034dfab7593a4b94066c12; webBuild=4.72.0; unread={%22ub%22:%22687338ef000000001d00f0ba%22%2C%22ue%22:%2268739fd9000000001703265f%22%2C%22uc%22:26}; loadts=1752423777445; acw_tc=0a4ad9b317524275626347245e7c600a016e1b6832a1b6feef86e40dfb6285; websectiga=59d3ef1e60c4aa37a7df3c23467bd46d7f1da0b1918cf335ee7f2e9e52ac04cf; sec_poison_id=2a1dd9b4-a73c-4ad7-8beb-fca89f464dec',
}

json_data = {
    'cursor_score': '',
    'num': 31,
    'refresh_type': 1,
    'note_index': 10,
    'unread_begin_note_id': '',
    'unread_end_note_id': '',
    'unread_note_count': 0,
    'category': 'homefeed.fashion_v3',
    'search_key': '',
    'need_num': 6,
    'image_formats': [
        'jpg',
        'webp',
        'avif',
    ],
    'need_filter_image': False,
}

response = requests.post('https://edith.xiaohongshu.com/api/sns/web/v1/homefeed', cookies=cookies, headers=headers, json=json_data).text

data_ = json.loads(response)
data = data_['data']['items']
for i in data:
    print(i)

关键点分析

  1. 环境检测:小红书会检测浏览器环境,需要完整模拟navigator、location等对象
  2. 参数构造:请求参数需要严格按照API要求的格式构造
  3. 编码顺序
    • 先计算参数MD5
    • 再使用mnsv2算法生成签名
    • 最后进行Base64编码
  4. 版本控制:x0字段代表API版本,需要与当前版本保持一致

注意事项

  1. mnsv2算法:是该签名的核心算法,需要单独实现
  2. 参数顺序:JSON.stringify的参数顺序会影响MD5结果
  3. 编码处理:Base64编码使用自定义字典,非标准实现
  4. 环境模拟:完整的浏览器环境模拟是签名成功的关键

总结

小红书Web端的X-S签名机制通过多层加密和编码确保请求安全性,完整实现需要:

  1. 精确模拟浏览器环境
  2. 正确构造请求参数
  3. 实现mnsv2核心算法
  4. 严格按照编码顺序处理