The verifier value computed by ComputeVerifier is a cryptographic secret that MUST be:
- Encrypted at rest in your database
- Protected with appropriate access controls
- Treated with the same care as password hashes
- Never transmitted over unencrypted connections
- Never logged or exposed in error messages
When using Server.Save() for stateless architectures:
- The returned state contains sensitive cryptographic material
- Always encrypt the state before storage (e.g., encrypted session store, JWE)
- Use authenticated encryption (e.g., AES-GCM)
- Set appropriate expiration times
- Never expose the state in URLs or logs
Recommended configuration for production:
import (
"crypto"
"runtime"
_ "crypto/sha256"
"golang.org/x/crypto/argon2"
"mz.attahri.com/code/srp/v2"
)
func SecureKDF(username, password string, salt []byte) ([]byte, error) {
p := []byte(username + ":" + password)
// Argon2id with reasonable parameters
key := argon2.IDKey(p, salt, 3, 256*1024, runtime.NumCPU(), 32)
return key, nil
}
var SecureParams = &srp.Params{
Name: "DH4096-SHA256-Argon2",
Group: srp.RFC5054Group4096, // 4096-bit or larger
Hash: crypto.SHA256, // SHA256 or stronger
KDF: SecureKDF, // Modern KDF (Argon2, scrypt)
}Do NOT use in production:
RFC5054Group1024orRFC5054Group1536(too small)RFC5054KDFwith SHA1 (deprecated, for RFC compatibility only)- Custom KDFs without proper password stretching
The library validates:
- Username: max 255 bytes (
MaxUsernameLength) - Password: max 1024 bytes (
MaxPasswordLength) - Salt: minimum 8 bytes (
MinSaltLength), default 16 bytes (SaltLength)
Applications SHOULD additionally:
- Enforce password complexity requirements
- Implement rate limiting on authentication attempts
- Monitor for brute force attacks
- Use account lockout mechanisms
Implement rate-limiting.
// Example: Implement rate limiting before SRP authentication
if rateLimiter.IsExceeded(username) {
return ErrTooManyAttempts
}
server, err := srp.NewServer(params, username, salt, verifier)
// ... continue SRP flowAlways use TLS when:
- Transmitting the verifier during registration
- Conducting SRP authentication
- Exchanging ephemeral keys (A, B, M1, M2)
SRP protects against eavesdropping on the password itself, but the protocol messages must still be protected against man-in-the-middle attacks.
- Generate salts with
NewSalt()orNewSaltWithLength() - Use a unique salt per user
- Salts can be public - they should be retrievable without authentication
- Minimum 8 bytes, recommended 12-16 bytes
- Never reuse salts across users
The shared session key from SessionKey():
- Is ephemeral and unique per session
- Can be used for additional encryption beyond TLS
- Should be cleared from memory after use
- Should have a limited lifetime
SRP protects against:
- Password database breaches (verifiers are not passwords)
- Passive eavesdropping
- Dictionary attacks on intercepted traffic
SRP does NOT protect against:
- Malware on client or server
- Phishing attacks
- Weak passwords
- Side-channel attacks
- Quantum computers (future threat)