From 85a9cfa1a67525ef2acc61f4f2f61fce139d13cc Mon Sep 17 00:00:00 2001 From: Justinas Stankevicius Date: Sun, 1 Jun 2014 12:53:09 +0300 Subject: [PATCH 1/2] Use constant-time comparison for credentials --- basic_auth.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/basic_auth.go b/basic_auth.go index 0181b11..577072a 100644 --- a/basic_auth.go +++ b/basic_auth.go @@ -1,6 +1,8 @@ package httpauth import ( + "crypto/sha256" + "crypto/subtle" "encoding/base64" "fmt" "net/http" @@ -63,8 +65,16 @@ func (b *basicAuth) authenticate(r *http.Request) bool { // allowable characters in the password. creds := strings.SplitN(string(str), ":", 2) + // Equalize lengths of supplied and required credentials + // by hashing them + givenUser := sha256.Sum256([]byte(creds[0])) + givenPass := sha256.Sum256([]byte(creds[1])) + requiredUser := sha256.Sum256([]byte(b.opts.User)) + requiredPass := sha256.Sum256([]byte(b.opts.Password)) + // Compare the supplied credentials to those set in our options - if creds[0] == b.opts.User && creds[1] == b.opts.Password { + if subtle.ConstantTimeCompare(givenUser[:], requiredUser[:]) == 1 && + subtle.ConstantTimeCompare(givenPass[:], requiredPass[:]) == 1 { return true } From 12a7749544f289cb41f3f9d3d6bbfc3e4ac6fc2f Mon Sep 17 00:00:00 2001 From: Justinas Stankevicius Date: Sun, 1 Jun 2014 13:07:51 +0300 Subject: [PATCH 2/2] Remove unnecessary conversions --- basic_auth.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/basic_auth.go b/basic_auth.go index 577072a..42af10d 100644 --- a/basic_auth.go +++ b/basic_auth.go @@ -1,6 +1,7 @@ package httpauth import ( + "bytes" "crypto/sha256" "crypto/subtle" "encoding/base64" @@ -63,12 +64,12 @@ func (b *basicAuth) authenticate(r *http.Request) bool { // Split on the first ":" character only, with any subsequent colons assumed to be part // of the password. Note that the RFC2617 standard does not place any limitations on // allowable characters in the password. - creds := strings.SplitN(string(str), ":", 2) + creds := bytes.SplitN(str, []byte(":"), 2) // Equalize lengths of supplied and required credentials // by hashing them - givenUser := sha256.Sum256([]byte(creds[0])) - givenPass := sha256.Sum256([]byte(creds[1])) + givenUser := sha256.Sum256(creds[0]) + givenPass := sha256.Sum256(creds[1]) requiredUser := sha256.Sum256([]byte(b.opts.User)) requiredPass := sha256.Sum256([]byte(b.opts.Password))