fix(auth): VerifyPassword 校验 PHC 参数上下界
t/p=0 会使 argon2.IDKey panic、m 超大可 OOM;越界一律返回 false(round2 P2-8),补畸形参数用例。
This commit is contained in:
+14
-2
@@ -40,7 +40,15 @@ func HashPassword(password string) (string, error) {
|
|||||||
), nil
|
), 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 {
|
func VerifyPassword(encoded, password string) bool {
|
||||||
parts := strings.Split(encoded, "$")
|
parts := strings.Split(encoded, "$")
|
||||||
// ["", "argon2id", "v=19", "m=..,t=..,p=..", salt, hash]
|
// ["", "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 {
|
if _, err := fmt.Sscanf(parts[3], "m=%d,t=%d,p=%d", &m, &t, &p); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if t < 1 || t > maxArgonTime || p < 1 || p > maxArgonThreads ||
|
||||||
|
m < 8 || m > maxArgonMemory {
|
||||||
|
return false
|
||||||
|
}
|
||||||
salt, err := base64.RawStdEncoding.DecodeString(parts[4])
|
salt, err := base64.RawStdEncoding.DecodeString(parts[4])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
want, err := base64.RawStdEncoding.DecodeString(parts[5])
|
want, err := base64.RawStdEncoding.DecodeString(parts[5])
|
||||||
if err != nil {
|
if err != nil || len(want) != KeyLen {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
got := argon2.IDKey([]byte(password), salt, t, m, p, uint32(len(want)))
|
got := argon2.IDKey([]byte(password), salt, t, m, p, uint32(len(want)))
|
||||||
|
|||||||
@@ -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) {
|
func TestTokenAndStrength(t *testing.T) {
|
||||||
tok, err := NewToken()
|
tok, err := NewToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user