2017-05-10 1 views
3

Je suis en train d'essayer de mettre en œuvre un webhook à bandes en utilisant la bibliothèque the C# Stripe.net de Jayme Davis. J'ai mis en place le point final de test dans le tableau de bord de bande et généré le secret. Le point de terminaison est en cours d'exécution et génère l'événement StripeEvent à l'aide de StripeEventUtility.ParseEvent. Le problème est avec l'utilisation de la fonction ConstructEvent je ne peux pas faire correspondre les signatures. Toute aide ou suggestion serait grandement appréciée.Échec de la signature webhook Stripe - Stripe.net

isSignaturePresent retourne faux

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

Comment initialisez-vous la variable 'json'? – Ywain

+0

J'utilise var json = JsonSerializer.SerializeToString (request); – stephen

+0

Vous resérialisez donc le corps de requête désérialisé. Cependant, il est très improbable que cela renvoie exactement la même chaîne que le corps de la demande d'origine. Vous devez utiliser le corps de la requête brute tel qu'il a été transmis par votre serveur/framework Web. – Ywain

Répondre

2

Je lui ai répondu dans les commentaires ci-dessus, mais pour résumer, la question est que la chaîne json fourni à la méthode ConstructEvent ne contenait pas la charge utile exacte envoyée par Stripe.

Au contraire, vous la charge utile avec l'initialisation:

var json = JsonSerializer.SerializeToString(request); 

vous dire reserialized corps de la demande désérialisé. Cependant, il est très peu probable que vous obteniez la même chaîne que la charge utile originale envoyée par Stripe. Par exemple. Stripe pourrait envoyer cette charge utile:

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

mais après désérialisation + resérialiser, votre chaîne JSON peut contenir cette valeur:

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

que l'ordre clé n'est pas garantie doit être maintenue, et d'autres options de formatage (newlines, indents) entrent en jeu.

Les signatures Webhook sont générées en utilisant la charge exacte (en tant que chaîne brute), donc lors de la vérification des signatures, vous devez également fournir cette charge utile exacte, telle que transmise par votre serveur ou framework Web.

+0

Ceci est la réponse acceptée. Merci Ywain – stephen

+0

De rien! :) – Ywain