Implement timing-safe string comparison for authentication

Prevents timing attacks where an attacker could deduce correct
credentials by measuring response times. Not sure if it is real threat,
but anyway.
This commit is contained in:
eleksir
2026-04-04 15:59:40 +03:00
parent 2201fc72f1
commit 7b001d710a

View File

@@ -2,6 +2,7 @@ package backer
import ( import (
"context" "context"
"crypto/subtle"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt" "fmt"
@@ -83,10 +84,8 @@ func NewServer(configPath string) (*ServerWrapper, error) {
return return
} }
// Both username AND password must match. Explicitly require that the whole condition // Both username AND password must match. Use timing-safe comparison to prevent timing attacks.
// fails when either is incorrect, per the authentication design. if !timingSafeMatch(username, C.User) || !timingSafeMatch(password, C.Password) {
//nolint:staticcheck // QF1001: De Morgan's law is irrelevant here.
if !(username == C.User && password == C.Password) {
w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`) w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized) http.Error(w, "Unauthorized", http.StatusUnauthorized)
@@ -321,4 +320,10 @@ func (sw *ServerWrapper) ServeTLS(certFile, keyFile string) error {
return err return err
} }
// timingSafeMatch performs constant-time comparison to prevent timing attacks.
// Returns 1 if the strings are equal, 0 otherwise.
func timingSafeMatch(a, b string) bool {
return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
}
/* vim: setlocal ft=go noet ai ts=4 sw=4 sts=4: */ /* vim: setlocal ft=go noet ai ts=4 sw=4 sts=4: */