Skip to content

Commit 15ccbcf

Browse files
committed
Remove weak hashes from BasicAuth
1 parent 2e544ae commit 15ccbcf

File tree

4 files changed

+4
-43
lines changed

4 files changed

+4
-43
lines changed

docs/middleware/basicauth.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ Getting the username and password
6666
Passwords must be supplied in pre-hashed form. The middleware detects the
6767
hashing algorithm from a prefix:
6868

69-
- `"{SHA512}"`, `"{SHA256}"`, or `"{SHA}"` followed by a base64 encoded digest
70-
- `"{MD5}"` followed by a base64 encoded digest
69+
- `"{SHA512}"` or `"{SHA256}"` followed by a base64 encoded digest
7170
- standard bcrypt strings beginning with `$2`
7271

7372
If no prefix is present the value is interpreted as a SHA-256 digest encoded in
@@ -92,7 +91,7 @@ func handler(c fiber.Ctx) error {
9291
| Charset | `string` | Charset sent in the `WWW-Authenticate` header, so clients know how credentials are encoded. | `"UTF-8"` |
9392
| HeaderLimit | `int` | Maximum allowed length of the `Authorization` header. Requests exceeding this limit are rejected. | `8192` |
9493
| StorePassword | `bool` | Store the plaintext password in the context and retrieve it via `PasswordFromContext`. | `false` |
95-
| Authorizer | `func(string, string, fiber.Ctx) bool` | Authorizer defines a function to check the credentials. It will be called with a username, password, and the current context and is expected to return true or false to indicate approval. | `nil` |
94+
| Authorizer | `func(string, string, fiber.Ctx) bool` | Authorizer defines a function to check the credentials. It will be called with a username, **hashed password**, and the current context and is expected to return true or false to indicate approval. | `nil` |
9695
| Unauthorized | `fiber.Handler` | Unauthorized defines the response body for unauthorized responses. | `nil` |
9796

9897
## Default Config

docs/whats_new.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1947,7 +1947,7 @@ Authorizer: func(user, pass string, _ fiber.Ctx) bool {
19471947
}
19481948
```
19491949
1950-
Passwords configured for BasicAuth must now be pre-hashed. If no prefix is supplied the middleware expects a SHA-256 digest encoded in hex. Common prefixes like `{SHA256}`, `{SHA}`, `{SHA512}`, `{MD5}` and bcrypt strings are also supported. Plaintext passwords are no longer accepted.
1950+
Passwords configured for BasicAuth must now be pre-hashed. If no prefix is supplied the middleware expects a SHA-256 digest encoded in hex. Common prefixes like `{SHA256}` and `{SHA512}` and bcrypt strings are also supported. Plaintext passwords are no longer accepted.
19511951
19521952
You can also set the optional `HeaderLimit`, `StorePassword`, and `Charset`
19531953
options to further control authentication behavior.

middleware/basicauth/basicauth_test.go

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

33
import (
4-
"crypto/md5" // #nosec G501 - test compatibility
5-
"crypto/sha1" // #nosec G505 - test compatibility
64
"crypto/sha256"
75
"crypto/sha512"
86
"encoding/base64"
@@ -28,16 +26,6 @@ func sha512Hash(p string) string {
2826
return "{SHA512}" + base64.StdEncoding.EncodeToString(sum[:])
2927
}
3028

31-
func sha1Hash(p string) string {
32-
sum := sha1.Sum([]byte(p)) // #nosec G401 - test compatibility
33-
return "{SHA}" + base64.StdEncoding.EncodeToString(sum[:])
34-
}
35-
36-
func md5Hash(p string) string {
37-
sum := md5.Sum([]byte(p)) // #nosec G401 - test compatibility
38-
return "{MD5}" + base64.StdEncoding.EncodeToString(sum[:])
39-
}
40-
4129
// go test -run Test_BasicAuth_Next
4230
func Test_BasicAuth_Next(t *testing.T) {
4331
t.Parallel()
@@ -370,8 +358,6 @@ func Test_parseHashedPassword(t *testing.T) {
370358
{"sha256", sha256Hash(pass)},
371359
{"sha256-hex", hexDigest},
372360
{"sha256-b64", b64},
373-
{"sha1", sha1Hash(pass)},
374-
{"md5", md5Hash(pass)},
375361
}
376362

377363
for _, tt := range cases {
@@ -398,8 +384,6 @@ func Test_BasicAuth_HashVariants(t *testing.T) {
398384
{"sha512", sha512Hash(pass)},
399385
{"sha256", sha256Hash(pass)},
400386
{"sha256-hex", func() string { h := sha256.Sum256([]byte(pass)); return hex.EncodeToString(h[:]) }()},
401-
{"sha1", sha1Hash(pass)},
402-
{"md5", md5Hash(pass)},
403387
}
404388

405389
for _, tt := range cases {
@@ -430,8 +414,6 @@ func Test_BasicAuth_HashVariants_Invalid(t *testing.T) {
430414
{"sha512", sha512Hash(pass)},
431415
{"sha256", sha256Hash(pass)},
432416
{"sha256-hex", func() string { h := sha256.Sum256([]byte(pass)); return hex.EncodeToString(h[:]) }()},
433-
{"sha1", sha1Hash(pass)},
434-
{"md5", md5Hash(pass)},
435417
}
436418

437419
for _, tt := range cases {

middleware/basicauth/config.go

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package basicauth
22

33
import (
4-
"crypto/md5" // #nosec G501 - compatibility with existing hashed passwords
5-
"crypto/sha1" // #nosec G505 - compatibility with existing hashed passwords
64
"crypto/sha256"
75
"crypto/sha512"
86
"crypto/subtle"
@@ -31,7 +29,7 @@ type Config struct {
3129

3230
// Authorizer defines a function you can pass
3331
// to check the credentials however you want.
34-
// It will be called with a username, password and
32+
// It will be called with a username, hashed password and
3533
// the current fiber context and is expected to return
3634
// true or false to indicate that the credentials were
3735
// approved or not.
@@ -165,24 +163,6 @@ func parseHashedPassword(h string) (func(string) bool, error) {
165163
sum := sha256.Sum256([]byte(p))
166164
return subtle.ConstantTimeCompare(sum[:], b) == 1
167165
}, nil
168-
case strings.HasPrefix(h, "{SHA}"):
169-
b, err := base64.StdEncoding.DecodeString(h[len("{SHA}"):])
170-
if err != nil {
171-
return nil, fmt.Errorf("decode SHA1 password: %w", err)
172-
}
173-
return func(p string) bool {
174-
sum := sha1.Sum([]byte(p)) // #nosec G401 - compatibility with existing hashed passwords
175-
return subtle.ConstantTimeCompare(sum[:], b) == 1
176-
}, nil
177-
case strings.HasPrefix(h, "{MD5}"):
178-
b, err := base64.StdEncoding.DecodeString(h[len("{MD5}"):])
179-
if err != nil {
180-
return nil, fmt.Errorf("decode MD5 password: %w", err)
181-
}
182-
return func(p string) bool {
183-
sum := md5.Sum([]byte(p)) // #nosec G401 - compatibility with existing hashed passwords
184-
return subtle.ConstantTimeCompare(sum[:], b) == 1
185-
}, nil
186166
default:
187167
b, err := hex.DecodeString(h)
188168
if err != nil || len(b) != sha256.Size {

0 commit comments

Comments
 (0)