Um eine Signaturprüfung für „X-Hub-Signature-256“ machen zu können muss man einen Hash erzeugen mit dem kompletten Body + dem Secret. Der Hash der hier erzeugt wird wird vom sender im Header „X-Hub-Signature-256“ mitgesendet. Sind die beiden Hashes gleich ist sichergestellt das der Body nicht verändert wurde und das das richtige Secret auf der anderen Seite verwendet wurde.
Das Problem auf das ich gestoßen bin ist das c.Request.Body ein Stream ist, wenn dieser einmal ausgelesen wurde dann steht dieser auf EOF. Somit war es nicht mehr möglich den Body mit c.ShouldBindJSON einzulesen, hier kommt wenn man die Error Variable ausließt der Hinweis EOF.
package main import ( "bytes" "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io" "io/ioutil" "log" "net/http" "github.com/gin-gonic/gin" ) func VerifySignature(payload []byte, signature string, secret string) bool { key := hmac.New(sha256.New, []byte(secret)) key.Write([]byte(string(payload))) computedSignature := "sha256=" + hex.EncodeToString(key.Sum(nil)) log.Printf("computed signature: %s", computedSignature) return computedSignature == signature } func Sync(c *gin.Context) { secret := "supersecret" // Generate copy of c.Request.Body bodyCopy := new(bytes.Buffer) _, err := io.Copy(bodyCopy, c.Request.Body) if err != nil { log.Println(err) c.JSON(http.StatusBadRequest, gin.H{"error": "Error reading API token"}) c.Abort() return } // Write copy to bodyData bodyData := bodyCopy.Bytes() // Replace the body with a reader that reads from the buffer c.Request.Body = io.NopCloser(bytes.NewReader(bodyData)) // Read body payload, _ := ioutil.ReadAll(c.Request.Body) // Set body again for c.ShouldBindJSON c.Request.Body = io.NopCloser(bytes.NewReader(bodyData)) // Verify signature if !VerifySignature(payload, c.GetHeader("X-Hub-Signature-256"), secret) { c.AbortWithStatus(http.StatusUnauthorized) log.Println("signatures don't match") } else { var jsonx interface{} err = c.ShouldBindJSON(&jsonx) if err != nil { fmt.Println("error:", err) } b, err := json.MarshalIndent(jsonx, "", " ") if err != nil { fmt.Println("error:", err) } fmt.Print(string(b)) } } func main() { r := gin.Default() r.POST("/sync", Sync) r.Run(":8080") }