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

.NET Framework 4.8下WCF服务中HMAC签名验证问题咨询

问题解答

问题1:.NET Framework 4.8中验证HMAC签名的替代方法

在.NET Framework 4.8中,没有内置的CryptographicOperations.FixedTimeEquals,但可以自行实现固定时间比较逻辑来完成HMAC签名验证,同时避免时序攻击(防止攻击者通过耗时差异猜测签名内容)。

固定时间比较的核心是遍历两个字节数组的所有元素,无论是否提前发现差异,都会完成全部比较,示例实现如下:

private static bool FixedTimeEquals(byte[] a, byte[] b)
{
    if (a.Length != b.Length)
        return false;

    int result = 0;
    for (int i = 0; i < a.Length; i++)
    {
        result |= a[i] ^ b[i];
    }
    return result == 0;
}

使用时,不要直接比较Base64字符串,而是将计算出的哈希字节数组与签名解码后的字节数组用该方法对比,安全性更高。

问题2:代码验证失败的原因分析

你的代码存在三个关键问题导致验证不通过:

  1. Payload序列化不一致
    你用JsonConvert.SerializeObject(jsonRequest)序列化模型对象,但DocuSign发送的是原始HTTP请求体,和序列化后的字符串可能存在属性顺序、空格、转义符、大小写等差异。正确做法是直接读取原始请求流:
HttpContext.Current.Request.InputStream.Position = 0;
using (var reader = new StreamReader(HttpContext.Current.Request.InputStream, Encoding.UTF8))
{
    var payload = reader.ReadToEnd();
}
  1. 字符串比较的潜在问题
    直接用string.Equals可能因大小写、编码等细节不匹配导致失败,且不具备固定时间比较的安全性。应先将签名头的Base64字符串解码为字节数组,再与计算出的哈希字节数组用固定时间方法对比。
  2. 密钥的一致性问题
    确保配置文件中的HMAC_Key与DocuSign控制台提供的原始密钥完全一致,无额外编码、截断或空格。

修复后的完整代码示例

public string DocuSign()
{
    // 读取原始请求体
    HttpContext.Current.Request.InputStream.Position = 0;
    string payload;
    using (var reader = new StreamReader(HttpContext.Current.Request.InputStream, Encoding.UTF8))
    {
        payload = reader.ReadToEnd();
    }

    var secretKey = ConfigurationManager.AppSettings["HMAC_Key"];
    var verifySignature = HttpContext.Current.Request.Headers["x-docusign-signature-1"];

    // 计算HMAC哈希
    byte[] secretBytes = Encoding.UTF8.GetBytes(secretKey);
    byte[] payloadBytes = Encoding.UTF8.GetBytes(payload);
    using (var hmac = new HMACSHA256(secretBytes))
    {
        byte[] computedHash = hmac.ComputeHash(payloadBytes);
        byte[] receivedHash = Convert.FromBase64String(verifySignature);
        
        // 固定时间比较验证签名
        bool valid = FixedTimeEquals(computedHash, receivedHash);
        return valid ? "Valid" : "Invalid";
    }
}

private static bool FixedTimeEquals(byte[] a, byte[] b)
{
    if (a.Length != b.Length)
        return false;

    int result = 0;
    for (int i = 0; i < a.Length; i++)
    {
        result |= a[i] ^ b[i];
    }
    return result == 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 17:52:33