本文作者:99ANYc3cd6

小红书API签名算法是如何实现的?具体步骤和参数解析是怎样的?

99ANYc3cd6 01-09 8
小红书API签名算法是如何实现的?具体步骤和参数解析是怎样的?摘要: 本文旨在学习和研究 API 安全机制,帮助你理解签名是如何工作的,请勿将此知识用于任何未经授权的爬取、滥用或破坏小红书平台的行为, 任何自动化操作都应严格遵守小红书的《用户服务协议...

本文旨在学习和研究 API 安全机制,帮助你理解签名是如何工作的。请勿将此知识用于任何未经授权的爬取、滥用或破坏小红书平台的行为。 任何自动化操作都应严格遵守小红书的《用户服务协议》和机器人协议(robots.txt),滥用 API 可能导致你的账号被封禁,并承担相应的法律责任。

小红书 API 的签名算法是其反爬虫和系统安全的核心,它确保了每一个 API 请求都经过了客户端的合法认证,防止请求被篡改,这套算法与许多国内大型互联网公司(如阿里巴巴、腾讯)的 API 签名逻辑非常相似,核心是 HMAC-SHA256 加密。

签名算法核心思想

小红书的签名机制可以概括为以下几个步骤:

  1. 参数准备:收集所有请求参数(包括 URL 查询参数、Body 中的 JSON 参数等),并进行排序和拼接。
  2. 构建待签名字符串:将排序后的参数、请求方法、请求路径等信息,按照特定格式拼接成一个长长的字符串。
  3. 生成签名:使用一个动态变化的密钥HMAC-SHA256 加密算法,对上一步的待签名字符串进行加密,生成一个十六进制的哈希值,这个值就是最终的签名。
  4. 附加签名:将生成的签名作为请求头(通常是 X-Secsdk-Csrf-Token)或请求参数,发送给服务器。

详细步骤分解

第 1 步:获取签名密钥

这是最关键也最困难的一步,小红书的签名密钥不是固定的,而是通过一个动态过程获取的,这个过程通常被称为“取 CSRF Token”或“取签名密钥”。

  • 入口点:通常需要先访问一个特定的、非加密的 HTTP 或 HTTPS 接口,这个接口可能是登录页、某个公共资源页,或者一个专门的“取签”接口。
  • :这个接口的响应体中会包含一个 JSON 对象,里面有一个关键的字段,data.xsecjsdata.token,这个字段的值就是临时的签名密钥
  • 密钥时效性:这个密钥通常有有效期(比如几小时或一天),过期后需要重新获取。

示例: 假设你访问 https://www.xiaohongshu.com/some/path/to/get/token,服务器返回:

{
  "code": 0,
  "data": {
    "xsecjs": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6"
  },
  "msg": "success"
}

a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6 就是接下来一段时间内你进行签名时要用到的密钥。

第 2 步:准备和排序参数

你需要收集所有参与签名的参数,这些参数通常包括:

  1. URL Query 参数?a=1&b=2&c=3 中的 a, b, c
  2. Body 中的 JSON 参数:如果是 POSTPUT 请求,Content-Typeapplication/json,JSON 对象里的所有键值对都属于参数。
  3. 固定参数:某些请求可能要求包含固定的参数,如 app_name, platform, version 等,这些通常在请求头或文档中说明。

排序规则:

  • 将所有参数的键(key)进行字典序(ASCII 顺序)升序排序。
  • 注意:这里的排序是区分大小写的。B 会排在 a 的前面。

示例: 假设你的原始参数是 c=3&b=2&a=1&d=4

  1. 提取键:['a', 'b', 'c', 'd']
  2. 排序后键:['a', 'b', 'c', 'd'] (已经是排好序的)

第 3 步:构建待签名字符串

将排序后的参数按照 key=value 的格式用 & 符号拼接起来。特别注意:这里的 value 必须是URL 编码后的值。

拼接格式: <sorted_params>&<http_method>&<request_path>

  • <sorted_params>:上一步排序并拼接好的字符串。
  • <http_method>:请求的 HTTP 方法,如 GET, POST必须大写
  • <request_path>:请求的相对路径,不包含域名和查询参数,请求 https://www.xiaohongshu.com/api/some/path?a=1,那么路径就是 /api/some/path

示例:

  • 排序后的参数:a=1&b=2&c=3&d=4
  • HTTP 方法:POST
  • 请求路径:/api/search/notes

待签名字符串就是: a=1&b=2&c=3&d=4&POST/api/search/notes

第 4 步:生成 HMAC-SHA256 签名

使用上一步获取的动态密钥和 HMAC-SHA256 算法对待签名字符串进行加密。

伪代码: signature = HMAC-SHA256(key, string_to_sign)

这里的 key 就是你从第 1 步获取的 xsecjs 值。string_to_sign 就是你构建的待签名字符串。

示例: 假设密钥是 my_secret_key,待签名字符串是 a=1&b=2&c=3&d=4&POST/api/search/notes。 生成的签名会是一个二进制数据,然后你需要将其转换为小写的十六进制字符串

第 5 步:附加签名并发送请求

将生成的十六进制签名附加到请求中,小红书 API 通常通过请求头来传递签名。

  • 请求头名称:通常是 X-Secsdk-Csrf-Token
  • 请求头值:就是上一步生成的十六进制签名。

最终请求头示例:

POST /api/search/notes HTTP/1.1
Host: www.xiaohongshu.com
Content-Type: application/json
X-Secsdk-Csrf-Token: 5f4dcc3b5aa765d61d8327deb882cf99 (这是一个示例,非真实值)
...

Python 代码示例

下面是一个用 Python 实现的简化版签名算法。

import hashlib
import hmac
import urllib.parse
import json
def generate_xiaohongshu_signature(params, http_method, request_path, secret_key):
    """
    生成小红书 API 签名
    :param params: 请求参数字典,{'a': 1, 'b': 2}
    :param http_method: HTTP 方法,如 'GET', 'POST' (必须大写)
    :param request_path: 请求路径,如 '/api/search/notes'
    :param secret_key: 从 API 获取的动态密钥
    :return: 生成的签名 (小写十六进制字符串)
    """
    # 1. 对参数的键进行排序
    sorted_keys = sorted(params.keys())
    # 2. 构建排序后的参数字符串 (key=value 并进行 URL 编码)
    sorted_params_list = []
    for key in sorted_keys:
        # 确保值被转换为字符串,并进行 URL 编码
        value = str(params[key])
        encoded_value = urllib.parse.quote(value, safe='')
        # 键也需要进行 URL 编码,以防万一
        encoded_key = urllib.parse.quote(key, safe='')
        sorted_params_list.append(f"{encoded_key}={encoded_value}")
    sorted_params_str = "&".join(sorted_params_list)
    # 3. 构建待签名字符串
    string_to_sign = f"{sorted_params_str}&{http_method}{request_path}"
    print(f"待签名字符串: {string_to_sign}")
    # 4. 使用 HMAC-SHA256 生成签名
    # hashlib.sha256 是哈希,hmac.new 才是 HMAC
    signature = hmac.new(
        secret_key.encode('utf-8'),  # 密钥需要是 bytes
        string_to_sign.encode('utf-8'),  # 待签名字符串也需要是 bytes
        hashlib.sha256
    )
    # 5. 返回小写的十六进制签名
    return signature.hexdigest()
# --- 示例用法 ---
if __name__ == "__main__":
    # 假设这是从某个接口获取到的动态密钥
    SECRET_KEY = "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6"
    # 假设这是你的请求参数
    request_params = {
        "keyword": "美食",
        "page": "1",
        "search_id": "1234567890abcdef"
    }
    # 请求方法和路径
    http_method = "POST"
    request_path = "/api/search/notes"
    # 生成签名
    signature = generate_xiaohongshu_signature(
        params=request_params,
        http_method=http_method,
        request_path=request_path,
        secret_key=SECRET_KEY
    )
    print(f"生成的签名: {signature}")
    # 在实际请求中,你需要将这个签名添加到请求头中
    # headers = {
    #     "X-Secsdk-Csrf-Token": signature,
    #     "Content-Type": "application/json"
    # }
    # ...

总结与挑战

  1. 动态密钥获取:最大的挑战在于如何稳定、可靠地获取那个动态的 secret_key,这个过程可能涉及解析 HTML、JS 代码,或者调用另一个隐藏的 API,网站更新时,这个获取流程也可能会失效。
  2. 参数完整性:你需要准确知道哪些参数参与了签名,哪些没有,遗漏任何一个参数都会导致签名错误。
  3. 时效性:密钥有有效期,你的代码需要具备定时刷新密钥的能力。
  4. 反爬虫升级:小红书作为头部内容平台,其反爬虫体系会不断升级,今天的算法明天可能就会改变,需要持续投入精力去分析和适配。

再次强调,理解这些机制有助于提升你的技术能力,但请务必在法律和道德允许的范围内使用,对于个人学习和研究,建议选择开放 API 或数据允许的平台进行实践。

文章版权及转载声明

作者:99ANYc3cd6本文地址:https://www.chumoping.net/post/8944.html发布于 01-09
文章转载或复制请以超链接形式并注明出处初梦运营网

阅读
分享