2017-05-10 98 views
3

我试图使用Jayme Davis的c#库Stripe.net实现条纹webhook。我已经在条形仪表板中设置了测试端点并生成了密钥。终点命中正常,并将使用StripeEventUtility.ParseEvent生成StripeEvent。问题是使用ConstructEvent函数我不能得到签名匹配。任何帮助或建议将不胜感激。条纹webhook签名失败 - Stripe.net

isSignaturePresent是返回false

//call to create event 
stripeEvent = ConstructEvent(json, Request.Headers["Stripe-Signature"], 
SecretFromStripeDashBoard); 


private StripeEvent ConstructEvent(string json, string 
stripeSignatureHeader, string secret, int tolerance = 300) 
    { 
     var signatureItems = parseStripeSignature(stripeSignatureHeader); 

     var signature = computeSignature(secret, signatureItems["t"].FirstOrDefault(), json); 

     if (!isSignaturePresent(signature, signatureItems["v1"])) 
      throw new Exception("The signature for the webhook is not present in the Stripe-Signature header."); 

     //var utcNow = EpochUtcNowOverride ?? DateTime.UtcNow.ConvertDateTimeToEpoch(); 
     //var webhookUtc = Convert.ToInt32(signatureItems["t"].FirstOrDefault()); 

     //if (utcNow - webhookUtc > tolerance) 
     // throw new Exception("The webhook cannot be processed because the current timestamp is above the allowed tolerance."); 

     return Mapper<StripeEvent>.MapFromJson(json); 
    } 

    private ILookup<string, string> parseStripeSignature(string stripeSignatureHeader) 
    { 
     return stripeSignatureHeader.Trim() 
      .Split(',') 
      .Select(item => item.Trim().Split('=')) 
      .ToLookup(item => item[0], item => item[1]); 
    } 

    private bool isSignaturePresent(string signature, IEnumerable<string> signatures) 
    { 
     return signatures.Any(key => secureCompare(key, signature)); 
    } 

    private string computeSignature(string secret, string timestamp, string payload) 
    { 
     var secretBytes = Encoding.UTF8.GetBytes(secret); 
     var payloadBytes = Encoding.UTF8.GetBytes($"{timestamp}.{payload}"); 

     var cryptographer = new HMACSHA256(secretBytes); 
     var hash = cryptographer.ComputeHash(payloadBytes); 

     return BitConverter.ToString(hash).Replace("-", "").ToLower(); 
    } 

    private bool secureCompare(string a, string b) 
    { 
     if (a.Length != b.Length) return false; 

     var result = 0; 

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

     return result == 0; 
    } 
} 
+0

你如何初始化'json'变量? – Ywain

+0

我使用var json = JsonSerializer.SerializeToString(request); – stephen

+0

所以你正在反序列化反序列化的请求体。但是,这很可能不会返回与原始请求主体完全相同的字符串。您需要使用由您的Web服务器/框架传递的原始请求主体。 – Ywain

回答

2

我回答在上述评论,但回顾一下,问题是,提供给ConstructEvent方法json串不包含由条纹发出的确切有效载荷。

相反,你初始化有效载荷:

var json = JsonSerializer.SerializeToString(request); 

即你reserialized反序列化要求的身体。但是,您很可能不会获得与Stripe发送的原始有效内容相同的字符串。例如。条纹可以发送该有效载荷:

{ 
    "a_key": "a_value", 
    "another_key": "another_value" 
} 

但反序列化+ reserializing后,你的JSON字符串可以包含以下值:

{"another_key": "another_value","a_key": "a_value"} 

为重点,顺序不能保证维持,和其他格式选项(换行符,缩进)发挥作用。

Webhook签名是使用确切负载(作为原始字符串)生成的,因此在验证签名时,还必须提供由Web服务器或框架传递的确切负载。

+0

这是被接受的答案。谢谢Ywain – stephen

+0

不客气! :) – Ywain