Can anyone help to verify Sendgrid signed webhook in node as the only example on the documentation is in Golang?

Viewed 573

I am trying to verify signature from the Sendgrid signed webhook. Current Sendgrid documentation only provides example in Golang to use ecdsa package.

They say that this can be achieved with Node crypto package but I don't have too much insight in crypto language.

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

Can anyone help me to parse the current Golang codebase to javascript?

// Golang Example
s := http.Request.Header.Get("X-Twilio-Email-Event-Webhook-Signature")
ts := http.Request.Header.Get("X-Twilio-Email-Event-Webhook-Timestamp")

signatureBytes, _ := base64.StdEncoding.DecodeString(s)
ecdsaSig := struct {
R *big.Int
S *big.Int
}

asn1.Unmarshal(signatureBytes, &ecdsaSig)

tsBytes := []byte(ts)
payload, _ := ioutil.ReadAll(http.Request.Body)
h := sha256.New()
h.Write(tsBytes)
h.Write(payload)
hashedPayload := h.Sum(nil)

ecdsa.Verify(publicKey, hashedPayload, ecdsaSig.R, ecdsaSig.S)
1 Answers

I use sendgrid-go eventwebhook helper to do signature verification, you can access the code here. The problem is, it only can verify single event webhook, so if multiple event (Exp: processed and delivered event in single request payload) the verification will failed. This bug currently reported in sendgrid-nodejs project here

import (
    "github.com/gin-gonic/gin"
    "github.com/sendgrid/sendgrid-go/helpers/eventwebhook"
)

const verkey  = "xxx"

func InsertHistory(c *gin.Context) {
    var results []map[string]interface{}
    if err := c.BindJSON(&results); err != nil {
        fmt.Println(err)
    }
    // Start checking Signature
    s := c.Request.Header.Get("X-Twilio-Email-Event-Webhook-Signature")
    ts := c.Request.Header.Get("X-Twilio-Email-Event-Webhook-Timestamp")

    payload := generatePayload(results)

    publicKey, _ := eventwebhook.ConvertPublicKeyBase64ToECDSA(verkey)
    b, err := eventwebhook.VerifySignature(publicKey, payload, s, ts)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("H.Signature: %s\nH.Timestamp: %s\nKey: %s\nPublicKey: %s\nVerified: %t", s, ts, verkey, publicKey, b)
}
Related