Skip to content

Commit 6149d9c

Browse files
committed
Constant time compare for admin password.
Using a constant time comparison for the admin password reduces the chance brute forcing the password via a side-channel/timing attack.
1 parent d9f1da2 commit 6149d9c

2 files changed

Lines changed: 29 additions & 20 deletions

File tree

internal/webapi/admin.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
// Copyright (c) 2020-2024 The Decred developers
1+
// Copyright (c) 2020-2025 The Decred developers
22
// Use of this source code is governed by an ISC
33
// license that can be found in the LICENSE file.
44

55
package webapi
66

77
import (
8+
"crypto/sha256"
9+
"crypto/subtle"
810
"encoding/json"
911
"net/http"
1012

@@ -263,7 +265,11 @@ func (w *WebAPI) adminLogin(c *gin.Context) {
263265

264266
password := c.PostForm("password")
265267

266-
if password != w.cfg.AdminPass {
268+
// subtle.ConstantTimeCompare returns immediately if the params are not the
269+
// same length. Avoid this by comparing hashes (which will be fixed length)
270+
// instead of the raw passwords.
271+
passwordHash := sha256.Sum256([]byte(password))
272+
if subtle.ConstantTimeCompare(passwordHash[:], w.adminPassHash[:]) != 1 {
267273
w.log.Warnf("Failed login attempt from %s", c.ClientIP())
268274
c.HTML(http.StatusUnauthorized, "login.html", gin.H{
269275
"WebApiCache": cacheData,

internal/webapi/webapi.go

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2020-2024 The Decred developers
1+
// Copyright (c) 2020-2025 The Decred developers
22
// Use of this source code is governed by an ISC
33
// license that can be found in the LICENSE file.
44

@@ -7,6 +7,7 @@ package webapi
77
import (
88
"context"
99
"crypto/ed25519"
10+
"crypto/sha256"
1011
"encoding/base64"
1112
"encoding/json"
1213
"errors"
@@ -67,15 +68,16 @@ const (
6768
)
6869

6970
type WebAPI struct {
70-
cfg Config
71-
db *database.VspDatabase
72-
log slog.Logger
73-
addrGen *addressGenerator
74-
cache *cache
75-
signPrivKey ed25519.PrivateKey
76-
signPubKey ed25519.PublicKey
77-
server *http.Server
78-
listener net.Listener
71+
cfg Config
72+
db *database.VspDatabase
73+
log slog.Logger
74+
addrGen *addressGenerator
75+
cache *cache
76+
adminPassHash [sha256.Size]byte
77+
signPrivKey ed25519.PrivateKey
78+
signPubKey ed25519.PublicKey
79+
server *http.Server
80+
listener net.Listener
7981
}
8082

8183
func New(vdb *database.VspDatabase, log slog.Logger, dcrd rpc.DcrdConnect,
@@ -121,14 +123,15 @@ func New(vdb *database.VspDatabase, log slog.Logger, dcrd rpc.DcrdConnect,
121123
}
122124

123125
w := &WebAPI{
124-
cfg: cfg,
125-
db: vdb,
126-
log: log,
127-
addrGen: addrGen,
128-
cache: cache,
129-
signPrivKey: signPrivKey,
130-
signPubKey: signPubKey,
131-
listener: listener,
126+
cfg: cfg,
127+
db: vdb,
128+
log: log,
129+
addrGen: addrGen,
130+
cache: cache,
131+
adminPassHash: sha256.Sum256([]byte(cfg.AdminPass)),
132+
signPrivKey: signPrivKey,
133+
signPubKey: signPubKey,
134+
listener: listener,
132135
}
133136

134137
w.server = &http.Server{

0 commit comments

Comments
 (0)