fix(auth): VerifyPassword 校验 PHC 参数上下界

t/p=0 会使 argon2.IDKey panic、m 超大可 OOM;越界一律返回 false(round2 P2-8),补畸形参数用例。
This commit is contained in:
2026-09-08 17:32:52 +08:00
parent a35e7fdfd3
commit ba7d5dd01f
2 changed files with 34 additions and 2 deletions
+14 -2
View File
@@ -40,7 +40,15 @@ func HashPassword(password string) (string, error) {
), nil
}
// VerifyPassword 按 PHC 串内参数重派生并常量时间比较。任何解析失败均返回 false。
// PHC 参数上下界(防畸形哈希触发 argon2 panic 或 OOM,评审 round2 P2-8):
// t/p 过小使 argon2.IDKey panic,m 过大直接耗尽内存。
const (
maxArgonTime = 10
maxArgonThreads = 8
maxArgonMemory = 1 << 20 // KiB(1 GiB),远大于现行 19456
)
// VerifyPassword 按 PHC 串内参数重派生并常量时间比较。任何解析失败或参数越界均返回 false。
func VerifyPassword(encoded, password string) bool {
parts := strings.Split(encoded, "$")
// ["", "argon2id", "v=19", "m=..,t=..,p=..", salt, hash]
@@ -57,12 +65,16 @@ func VerifyPassword(encoded, password string) bool {
if _, err := fmt.Sscanf(parts[3], "m=%d,t=%d,p=%d", &m, &t, &p); err != nil {
return false
}
if t < 1 || t > maxArgonTime || p < 1 || p > maxArgonThreads ||
m < 8 || m > maxArgonMemory {
return false
}
salt, err := base64.RawStdEncoding.DecodeString(parts[4])
if err != nil {
return false
}
want, err := base64.RawStdEncoding.DecodeString(parts[5])
if err != nil {
if err != nil || len(want) != KeyLen {
return false
}
got := argon2.IDKey([]byte(password), salt, t, m, p, uint32(len(want)))
+20
View File
@@ -31,6 +31,26 @@ func TestPasswordHashRoundtrip(t *testing.T) {
}
}
// TestVerifyPasswordMalformedParams 畸形 PHC 参数安全返回 false:
// t/p=0 会使 argon2.IDKey panic、m 巨大会 OOM(评审 round2 P2-8)。
func TestVerifyPasswordMalformedParams(t *testing.T) {
salt := "AAAAAAAAAAAAAAAAAAAAAA" // 16 字节 base64(raw std)
hash := "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" // 32 字节
bad := []string{
"$argon2id$v=19$m=19456,t=0,p=1$" + salt + "$" + hash,
"$argon2id$v=19$m=19456,t=2,p=0$" + salt + "$" + hash,
"$argon2id$v=19$m=999999999,t=2,p=1$" + salt + "$" + hash,
"$argon2id$v=19$m=19456,t=999,p=1$" + salt + "$" + hash,
"$argon2id$v=19$m=19456,t=2,p=99$" + salt + "$" + hash,
"$argon2id$v=19$m=19456,t=2,p=1$" + salt + "$AAAA", // 哈希长度异常
}
for _, h := range bad {
if VerifyPassword(h, "x") {
t.Errorf("畸形参数不应通过: %s", h)
}
}
}
func TestTokenAndStrength(t *testing.T) {
tok, err := NewToken()
if err != nil {