Why should you compare secrets with crypto/subtle.ConstantTimeCompare instead of ==? How do you hash passwords in Go?
== and bytes.Equal return as soon as they hit the first byte that differs. By measuring response times over many requests, an attacker can recover a token or HMAC byte by byte. That is a timing side channel. subtle.ConstantTimeCompare(a, b) returns 1 or 0, and for equal-length inputs its running time depends only on the length. Gotcha: it returns 0 immediately when the lengths differ, which leaks the length. For secrets of variable length, hash both sides first. For MACs, use hmac.Equal.
func validAPIKey(got, want string) bool {
g := sha256.Sum256([]byte(got))
w := sha256.Sum256([]byte(want))
return subtle.ConstantTimeCompare(g[:], w[:]) == 1
}
// Passwords: slow, salted, adaptive hash (golang.org/x/crypto/bcrypt)
hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost) // cost 10; tune to ~100ms+
if err != nil {
return err // includes bcrypt.ErrPasswordTooLong for >72 bytes
}
if err := bcrypt.CompareHashAndPassword(hash, []byte(attempt)); err != nil {
return errInvalidCredentials // constant-time internally
}
// Or Argon2id (golang.org/x/crypto/argon2) - memory-hard, OWASP-preferred
salt := make([]byte, 16)
rand.Read(salt) // crypto/rand
key := argon2.IDKey([]byte(pw), salt, 1, 64*1024, 4, 32) // store salt+params+key
Never store passwords as plain SHA-256 or MD5. Those hashes are fast, so GPUs can brute-force them. bcrypt stores the salt and cost inside the hash string. What the interviewer is looking for: the timing leak, the length caveat, the difference between a password KDF (bcrypt, scrypt, Argon2id) and a plain hash, and the fact that crypto/pbkdf2 joined the standard library in Go 1.24, which helps with FIPS requirements.
More on More Standard Library Essentials
- Q536text/template vs html/template: how does contextual auto-escaping prevent XSS, and what does template.HTML bypass?
- Q537How do you prevent SQL injection with database/sql? Why can't placeholders be used for table names or ORDER BY columns?
- Q539How does regexp (RE2) differ from PCRE engines? Why doesn't Go support backreferences, and what are the performance guarantees?
- Q540How do you run external commands safely with os/exec? Explain CommandContext, capturing stdout/stderr, exit codes, and why shell injection is not the default risk.
- Q541How do you build a TCP server with net.Listen? Handle per-connection goroutines, read/write deadlines, and graceful shutdown of the listener.
- Q542Explain io/fs and fs.FS. How do you walk a directory with filepath.WalkDir and test file-system code with testing/fstest.MapFS?