You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何验证Moralis Streams API的x-signature请求头?

Moralis Streams Webhook x-signature 验证失败问题解决

问题背景

在处理Moralis Streams API的入站Webhook请求时,按照官方文档说明,x-signature是请求体与API密钥拼接后的SHA3-256哈希值,但C#实现的签名验证始终不匹配。现有代码直接读取原始请求体拼接密钥后计算哈希,但生成的签名与请求头中的值长度一致却不匹配。从官方JS SDK中发现签名计算逻辑为:

const generatedSignature = sha3(JSON.stringify(body) + secret);

核心原因

Moralis Streams服务端基于Node.js实现,生成x-signature时依赖JavaScript标准的JSON.stringify()序列化规则,而非原始请求体的字节内容。JSON.stringify()有特定的格式要求:

  • 默认无缩进、无多余空格
  • 字符串转义规则与C#默认JSON序列化存在差异
  • 键的顺序遵循对象属性的插入顺序(与C#中某些序列化器的排序逻辑不同)

直接读取原始请求体拼接密钥的方式,无法保证和JSON.stringify(body)的输出完全一致,导致最终哈希结果不匹配。

正确的C#验证实现

要匹配Moralis的签名逻辑,需模拟JSON.stringify()的行为处理请求体,再计算哈希。以下是修正后的代码:

1. 核心验证逻辑

var signature = Request.Headers["x-signature"].FirstOrDefault();

if (string.IsNullOrEmpty(signature))
{
    logger.LogInformation("No signature was present from webhook request, ignoring.");
    return Ok();
}

Request.EnableBuffering();

// 读取原始请求体
using var reader = new StreamReader(Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true);
var rawBody = await reader.ReadToEndAsync();
Request.Body.Position = 0;

try
{
    // 反序列化为JObject(兼容任意结构的Webhook payload)
    var bodyObject = JsonSerializer.Deserialize<JObject>(rawBody);

    // 配置序列化选项,匹配JSON.stringify的行为
    var jsSerializeOptions = new JsonSerializerOptions
    {
        WriteIndented = false, // 禁用缩进,对应JSON.stringify默认行为
        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, // 避免额外字符转义
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // 匹配JS的驼峰命名(根据实际payload调整)
        DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
    };

    // 重新序列化为符合JS格式的JSON字符串
    var jsCompatibleJson = JsonSerializer.Serialize(bodyObject, jsSerializeOptions);

    // 拼接Streams密钥
    var dataToHash = jsCompatibleJson + "<你的Streams Secret>";

    // 计算SHA3-256哈希
    var hashBytes = SHA3_256.HashData(Encoding.UTF8.GetBytes(dataToHash));
    var computedSignature = "0x" + Convert.ToHexString(hashBytes).ToLower();

    // 验证签名
    if (signature != computedSignature)
    {
        logger.LogInformation("Signature was incorrect from webhook, ignoring");
        return Ok();
    }
}
catch (JsonException ex)
{
    logger.LogError(ex, "Failed to parse webhook body");
    return Ok();
}

// 签名验证通过,继续处理业务逻辑

2. 注意事项

  • 确保JsonSerializerOptions的配置与你的Webhook payload结构匹配,比如如果payload的键是蛇形命名,需调整PropertyNamingPolicy为null
  • 若使用.NET版本低于5.0,Convert.ToHexString可替换为你原有的BytesToHex方法,注意保持十六进制字符为小写
  • 必须使用SHA3-256哈希算法,不要混淆为SHA256或其他哈希类型

内容的提问来源于stack exchange,提问作者Ethan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 10:25:00