fix: dual-key rate limiting for auth + websocket reconnect guard
- Pass client IP (X-Real-IP header) through Flask to daemon for both password login and WebAuthn authenticate-finish endpoints - Rate limiter now checks both IP and username buckets: IP layer catches enumeration/brute-force attacks across multiple usernames; username layer protects against single-account targeting from multiple IPs - Add _wsRefreshing flag to prevent double-scheduling reconnect when onclose fires during token refresh; simplify async IIFE to .then()/.catch() - Reset _wsRefreshing on websocket onopen for safety
This commit is contained in:
+11
-2
@@ -394,25 +394,34 @@ _login_limiter = RateLimiter(max_attempts=10, window_seconds=300)
|
||||
_webauthn_limiter = RateLimiter(max_attempts=5, window_seconds=600)
|
||||
|
||||
|
||||
def check_login_rate(username: str) -> bool:
|
||||
def check_login_rate(username: str, client_ip: str | None = None) -> bool:
|
||||
"""Check if login is rate-limited for the given username.
|
||||
|
||||
Uses dual-key tracking: always records by IP (catches enumeration attacks),
|
||||
additionally records by username (catches legitimate users who forget password).
|
||||
|
||||
Args:
|
||||
username: The login attempt username.
|
||||
client_ip: The client IP address (from X-Real-IP header).
|
||||
|
||||
Returns:
|
||||
True if the attempt is allowed, False if rate limited.
|
||||
"""
|
||||
if client_ip and not _login_limiter.is_allowed(client_ip):
|
||||
return False
|
||||
return _login_limiter.is_allowed(username)
|
||||
|
||||
|
||||
def check_webauthn_rate(username: str) -> bool:
|
||||
def check_webauthn_rate(username: str, client_ip: str | None = None) -> bool:
|
||||
"""Check if WebAuthn authentication is rate-limited for the given username.
|
||||
|
||||
Args:
|
||||
username: The WebAuthn attempt username.
|
||||
client_ip: The client IP address (from X-Real-IP header).
|
||||
|
||||
Returns:
|
||||
True if the attempt is allowed, False if rate limited.
|
||||
"""
|
||||
if client_ip and not _webauthn_limiter.is_allowed(client_ip):
|
||||
return False
|
||||
return _webauthn_limiter.is_allowed(username)
|
||||
|
||||
Reference in New Issue
Block a user