【问题标题】:Verifying SendGrid's Signed Event Webhook?验证 SendGrid 的签名事件 Webhook?
【发布时间】:2020-06-17 15:29:47
【问题描述】:

我正在尝试通过此链接实施验证。

https://sendgrid.com/docs/for-developers/tracking-events/getting-started-event-webhook-security-features/#the-signed-event-webhook

我不想要其中的 OAuth 部分,而是使用公钥和标头来验证数据。我看过很多与 SendGrid 的 Event Webhook 相关的帖子,但没有什么可以验证的。

这是我尝试过的,但显然有问题。我真的不确定如何将文档中的代码翻译成 C#。我不确定请求中的每条数据应该去哪里。有人对此有任何见解吗?

public async Task<IHttpActionResult> EventsHook()
{
    IEnumerable<string> signatureFromHeader = Request.Headers.GetValues("X-Twilio-Email-Event-Webhook-Signature");
    byte[] timeStampBytes = Encoding.ASCII.GetBytes(Request.Headers.GetValues("X-Twilio-Email-Event-Webhook-Timestamp").First());
    byte[] body = await Request.Content.ReadAsByteArrayAsync();
    byte[] payloadHash = timeStampBytes.Concat(body).ToArray();
    byte[] signatureByteArray = Convert.FromBase64String(signatureFromHeader.First());
    var publicKey = "{myPublicKey}";
    byte[] publicKeyBytes = Convert.FromBase64String(publicKey);

    var ecdsaParams = new ECParameters
    {
        D = publicKeyBytes
    };

    using (var ecdsa = ECDsa.Create(ecdsaParams))
    {
        if (ecdsa.VerifyData(payloadHash, signatureByteArray, HashAlgorithmName.SHA256))
        {
            return Ok();
        }
        return StatusCode(System.Net.HttpStatusCode.Forbidden);
    }
}

【问题讨论】:

    标签: c# sendgrid ecdsa webapi


    【解决方案1】:

    我刚刚实现了这个,我可以帮你解决这个问题:

    1- 我使用库starkbank-ecdsa 来验证签名。 2- 我声明了这个接口

    public interface IEmailWebHookRequestValidator
    {
        bool IsValidRequest(HttpRequest request);
    }
    

    3-这个接口的实现是这样的:

    public class SendGridWebHookRequestValidator : IEmailWebHookRequestValidator
    {
       private const string SIGNATURE_HEADER = "X-Twilio-Email-Event-Webhook-Signature";
       private const string TIMESTAMP_HEADER = "X-Twilio-Email-Event-Webhook-Timestamp";
        
       private readonly string _sendGridWebHookPublicKey;
        
       public SendGridWebHookRequestValidator(ISettingsProvider settingsProvider)
       {
          _sendGridWebHookPublicKey = settingsProvider.SendGridWebHookPublicKey //"public key that you can get from SendGrid website when you enable Event Webhook's signature";
       }
        
       public bool IsValidRequest(HttpRequest request)
       {
          request.Headers.TryGetValue(SIGNATURE_HEADER, out var signatureHeaderValues);
          request.Headers.TryGetValue(TIMESTAMP_HEADER, out var timestampHeaderValues);
        
          var signature = signatureHeaderValues.FirstOrDefault();
          var timestamp = timestampHeaderValues.FirstOrDefault();
        
          if (string.IsNullOrWhiteSpace(signature) || string.IsNullOrWhiteSpace(timestamp))
          {
             return false;
          }
        
          var body = ReadStream(request.Body);
        
          return VerifySignature(_sendGridWebHookPublicKey, body, signature, timestamp);
       }
        
    
       public bool VerifySignature(string verificationKey, string payload, string signature, string timestamp)
       {
          var publicKey = PublicKey.fromPem(verificationKey);
        
          var timestampedPayload = timestamp + payload;
          var decodedSignature = Signature.fromBase64(signature);
        
          return Ecdsa.verify(timestampedPayload, decodedSignature, publicKey);
       }
        
       public static string ReadStream(Stream stream)
       {
           using var ms = new MemoryStream();
        
           stream.CopyTo(ms);
           return Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length);
       }
    }
    
    1. ISettingsProvider 只是一个帮助您从设置中检索公钥的接口。

    2. 当您的 webhook 接收到 httprequest 时,只需将其传递给 IsValidRequest 方法即可轻松使用上述代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-16
      • 2020-07-17
      • 2021-12-25
      • 2022-06-28
      • 2023-01-04
      • 2019-05-11
      • 2020-08-22
      • 1970-01-01
      相关资源
      最近更新 更多