2017-05-10 3 views
3

Im Versuch, eine Stripe Webhook mit der C# -Bibliothek Stripe.net von Jayme Davis zu implementieren. Ich habe den Test-Endpunkt im Stripe-Dashboard eingerichtet und das Geheimnis generiert. Der Endpunkt wird gut getroffen und generiert das StripeEvent mithilfe von StripeEventUtility.ParseEvent. Das Problem liegt in der Verwendung der ConstructEvent-Funktion, die die Übereinstimmung der Signaturen nicht erreichen kann. Jede Hilfe oder Vorschläge wären sehr willkommen.Stripe Webhook Unterschrift fehlgeschlagen - Stripe.net

isSignaturePresent kehrt falsch

//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

Wie initialisierst du die Variable 'json'? – Ywain

+0

ich benutze var json = JsonSerializer.SerializeToString (Anfrage); – stephen

+0

Sie reservieren also den deserialisierten Anfragetext. Es ist jedoch sehr unwahrscheinlich, dass dies genau die gleiche Zeichenfolge wie der ursprüngliche Anfragetext zurückgibt. Sie müssen den rohen Anfragetext verwenden, wie er von Ihrem Webserver/Framework übergeben wurde. – Ywain

Antwort

2

ich oben in den Kommentaren beantwortet, aber zu rekapitulieren, das Problem war, dass die json Zeichenfolge an den ConstructEvent Verfahren bereitgestellt nicht die genaue Nutzlast von Streifen geschickt enthielt.

Vielmehr initialisiert Sie die Nutzlast mit:

var json = JsonSerializer.SerializeToString(request); 

heißt Sie die entserialisierten Anfrage Körper neu serialisiert. Es ist jedoch sehr unwahrscheinlich, dass Sie die gleiche Zeichenkette wie die ursprüngliche von Stripe gesendete Nutzlast erhalten. Z.B. Streifen könnte diese Nutzlast senden:

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

aber nach Deserialisieren + reserializing, Ihr JSON-String diesen Wert enthalten könnte:

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

als der Schlüssel, um nicht aufrechterhalten werden garantiert, und andere Formatierungsoptionen (Zeilenumbrüche, Gedankenstriche) ins Spiel kommen.

Webhooksignaturen werden mit der exakten Nutzlast (als rohe Zeichenfolge) generiert. Wenn Sie also Signaturen überprüfen, müssen Sie genau die Payload angeben, die von Ihrem Webserver oder Framework übergeben wird.

+0

Dies ist die akzeptierte Antwort. Danke Ywain – stephen

+0

Gern geschehen! :) – Ywain

Verwandte Themen