Stripe webhook signature failed - Stripe.net

时光总嘲笑我的痴心妄想 提交于 2019-12-23 12:43:22

问题


Im trying to implement a stripe webhook using the the c# library Stripe.net by Jayme Davis. i have set up the test endpoint in the stripe dashboard and generated the secret. The endpoint is being hit fine, and will generate the StripeEvent using the StripeEventUtility.ParseEvent. The problem is with using the ConstructEvent function i cant get the signatures to match. Any help or suggestions would be much appreciated.

isSignaturePresent is returning 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;
    }
}

回答1:


I answered in comments above, but to recap, the issue was that the json string provided to the ConstructEvent method did not contain the exact payload sent by Stripe.

Rather, you initialized the payload with:

var json = JsonSerializer.SerializeToString(request);

i.e. you reserialized the deserialized request's body. However, it's very unlikely that you would get the same string as the original payload sent by Stripe. E.g. Stripe could send this payload:

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

but after deserializing+reserializing, your JSON string could contain this value:

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

as the key order is not guaranteed to be maintained, and other formatting options (newlines, indents) come into play.

Webhook signatures are generated using the exact payload (as a raw string), so when verifying signatures, you must also provide that exact payload, as passed by your web server or framework.



来源:https://stackoverflow.com/questions/43888618/stripe-webhook-signature-failed-stripe-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!