Skip to content

Commit 7647123

Browse files
authored
Make Gitlab token verification constant time (#165)
This prevents leakage of token information using timing attacks. A simple string comparison does not suffice here. It's also good practice to hash first to prevent leakage of the length of the secret, as `subtle.ConstantTimeCompare` has the undesired behavior of returning early if the length of the two given byte slices does not match. A hash function always generates a byte slice of constant length though.
1 parent ec393fa commit 7647123

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

gitlab/gitlab.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package gitlab
22

33
import (
4+
"crypto/sha512"
5+
"crypto/subtle"
46
"encoding/json"
57
"errors"
68
"fmt"
@@ -53,14 +55,16 @@ type WebhookOptions struct{}
5355
// Secret registers the GitLab secret
5456
func (WebhookOptions) Secret(secret string) Option {
5557
return func(hook *Webhook) error {
56-
hook.secret = secret
58+
// already convert here to prevent timing attack (conversion depends on secret)
59+
hash := sha512.Sum512([]byte(secret))
60+
hook.secretHash = hash[:]
5761
return nil
5862
}
5963
}
6064

6165
// Webhook instance contains all methods needed to process events
6266
type Webhook struct {
63-
secret string
67+
secretHash []byte
6468
}
6569

6670
// Event defines a GitLab hook event type by the X-Gitlab-Event Header
@@ -91,10 +95,10 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
9195
return nil, ErrInvalidHTTPMethod
9296
}
9397

94-
// If we have a Secret set, we should check the MAC
95-
if len(hook.secret) > 0 {
96-
signature := r.Header.Get("X-Gitlab-Token")
97-
if signature != hook.secret {
98+
// If we have a Secret set, we should check in constant time
99+
if len(hook.secretHash) > 0 {
100+
tokenHash := sha512.Sum512([]byte(r.Header.Get("X-Gitlab-Token")))
101+
if subtle.ConstantTimeCompare(tokenHash[:], hook.secretHash[:]) == 0 {
98102
return nil, ErrGitLabTokenVerificationFailed
99103
}
100104
}

0 commit comments

Comments
 (0)