Browse Source

Add rate limiting for TOTP auth attempts

pull/551/head
Pēteris Caune 3 years ago
parent
commit
8ed5e93cd2
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
3 changed files with 20 additions and 0 deletions
  1. +9
    -0
      hc/accounts/tests/test_login_totp.py
  2. +3
    -0
      hc/accounts/views.py
  3. +8
    -0
      hc/api/models.py

+ 9
- 0
hc/accounts/tests/test_login_totp.py View File

@ -1,6 +1,7 @@
import time import time
from unittest.mock import patch from unittest.mock import patch
from hc.api.models import TokenBucket
from hc.test import BaseTestCase from hc.test import BaseTestCase
@ -75,3 +76,11 @@ class LoginTotpTestCase(BaseTestCase):
r = self.client.post(self.url, {"code": "000000"}) r = self.client.post(self.url, {"code": "000000"})
self.assertContains(r, "The code you entered was incorrect.") self.assertContains(r, "The code you entered was incorrect.")
def test_it_uses_rate_limiting(self):
obj = TokenBucket(value=f"totp-{self.alice.id}")
obj.tokens = 0
obj.save()
r = self.client.post(self.url, {"code": "000000"})
self.assertContains(r, "Too Many Requests")

+ 3
- 0
hc/accounts/views.py View File

@ -848,6 +848,9 @@ def login_totp(request):
totp = pyotp.totp.TOTP(user.profile.totp) totp = pyotp.totp.TOTP(user.profile.totp)
if request.method == "POST": if request.method == "POST":
if not TokenBucket.authorize_totp(user):
return render(request, "try_later.html")
form = forms.TotpForm(totp, request.POST) form = forms.TotpForm(totp, request.POST)
if form.is_valid(): if form.is_valid():
request.session.pop("2fa_user") request.session.pop("2fa_user")


+ 8
- 0
hc/api/models.py View File

@ -983,3 +983,11 @@ class TokenBucket(models.Model):
# 10 sudo attempts per day # 10 sudo attempts per day
return TokenBucket.authorize(value, 10, 3600 * 24) return TokenBucket.authorize(value, 10, 3600 * 24)
@staticmethod
def authorize_totp(user):
value = "totp-%d" % user.id
# 96 attempts per 24 hours
# (or, on average, one attempt per 15 minutes)
return TokenBucket.authorize(value, 96, 3600 * 24)

Loading…
Cancel
Save