diff options
author | Brendan Abolivier <contact@brendanabolivier.com> | 2019-03-18 12:57:20 +0000 |
---|---|---|
committer | Richard van der Hoff <1389908+richvdh@users.noreply.github.com> | 2019-03-18 12:57:20 +0000 |
commit | 651ad8bc96d360500e7f5953d05ef418b51acc86 (patch) | |
tree | eb02892a8aec9fb521e2fc5496d9e74985a04986 /synapse/handlers | |
parent | Add ratelimiting on login (#4821) (diff) | |
download | synapse-651ad8bc96d360500e7f5953d05ef418b51acc86.tar.xz |
Add ratelimiting on failed login attempts (#4865)
Diffstat (limited to 'synapse/handlers')
-rw-r--r-- | synapse/handlers/auth.py | 28 |
1 files changed, 23 insertions, 5 deletions
diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py index 74f3790f25..caad9ae2dd 100644 --- a/synapse/handlers/auth.py +++ b/synapse/handlers/auth.py @@ -101,6 +101,7 @@ class AuthHandler(BaseHandler): self._supported_login_types = login_types self._account_ratelimiter = Ratelimiter() + self._failed_attempts_ratelimiter = Ratelimiter() self._clock = self.hs.get_clock() @@ -729,9 +730,16 @@ class AuthHandler(BaseHandler): if not known_login_type: raise SynapseError(400, "Unknown login type %s" % login_type) - # unknown username or invalid password. We raise a 403 here, but note - # that if we're doing user-interactive login, it turns all LoginErrors - # into a 401 anyway. + # unknown username or invalid password. + self._failed_attempts_ratelimiter.ratelimit( + qualified_user_id.lower(), time_now_s=self._clock.time(), + rate_hz=self.hs.config.rc_login_failed_attempts.per_second, + burst_count=self.hs.config.rc_login_failed_attempts.burst_count, + update=True, + ) + + # We raise a 403 here, but note that if we're doing user-interactive + # login, it turns all LoginErrors into a 401 anyway. raise LoginError( 403, "Invalid password", errcode=Codes.FORBIDDEN @@ -956,13 +964,23 @@ class AuthHandler(BaseHandler): def ratelimit_login_per_account(self, user_id): """Checks whether the process must be stopped because of ratelimiting. + Checks against two ratelimiters: the generic one for login attempts per + account and the one specific to failed attempts. + Args: user_id (unicode): complete @user:id Raises: - LimitExceededError if the ratelimiter's login requests count for this - user is too high too proceed. + LimitExceededError if one of the ratelimiters' login requests count + for this user is too high too proceed. """ + self._failed_attempts_ratelimiter.ratelimit( + user_id.lower(), time_now_s=self._clock.time(), + rate_hz=self.hs.config.rc_login_failed_attempts.per_second, + burst_count=self.hs.config.rc_login_failed_attempts.burst_count, + update=False, + ) + self._account_ratelimiter.ratelimit( user_id.lower(), time_now_s=self._clock.time(), rate_hz=self.hs.config.rc_login_account.per_second, |