fix: P0-02 prevent login attempt counter race condition
Add atomic Increment method to cache layers: - L2Cache interface: add Increment method signature - RedisCache: implement using Redis INCRBY - L1Cache: implement with mutex-protected counter - CacheManager: add Increment that updates both L1 and L2 Update incrementFailAttempts to use atomic Increment instead of Get-Increment-Set pattern, preventing TOCTOU race.
This commit is contained in:
@@ -494,17 +494,23 @@ func (s *AuthService) incrementFailAttempts(ctx context.Context, key string) int
|
||||
return 0
|
||||
}
|
||||
|
||||
current := 0
|
||||
if value, ok := s.cache.Get(ctx, key); ok {
|
||||
current = attemptCount(value)
|
||||
}
|
||||
current++
|
||||
|
||||
if err := s.cache.Set(ctx, key, current, s.loginLockDuration, s.loginLockDuration); err != nil {
|
||||
log.Printf("auth: store login attempts failed, key=%s err=%v", key, err)
|
||||
// 使用原子递增,避免竞态条件
|
||||
newVal, err := s.cache.Increment(ctx, key, 1, s.loginLockDuration)
|
||||
if err != nil {
|
||||
log.Printf("auth: increment login attempts failed, key=%s err=%v", key, err)
|
||||
// 回退到原来的非原子方式
|
||||
current := 0
|
||||
if value, ok := s.cache.Get(ctx, key); ok {
|
||||
current = attemptCount(value)
|
||||
}
|
||||
current++
|
||||
if setErr := s.cache.Set(ctx, key, current, s.loginLockDuration, s.loginLockDuration); setErr != nil {
|
||||
log.Printf("auth: store login attempts failed, key=%s err=%v", key, setErr)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
return current
|
||||
return int(newVal)
|
||||
}
|
||||
|
||||
func isValidPhoneSimple(phone string) bool {
|
||||
|
||||
Reference in New Issue
Block a user