Skip to content
This repository has been archived by the owner on Sep 10, 2024. It is now read-only.

Rate-limit password-based login attempts #3013

Merged
merged 2 commits into from
Jul 26, 2024
Merged

Rate-limit password-based login attempts #3013

merged 2 commits into from
Jul 26, 2024

Conversation

sandhose
Copy link
Member

This is a first step for #2541.

It sets up a Limiter utility, which will hold all the rate-limiting logic.
As a first candidate, I rate-limited password-based logins.

There are two levels of rate-limiting:

  • per-IP address, which has a low limit (3 per minute)
  • per-user, which has a higher limit (1800 per hour)

I'm hesitant about the latter, but this is to try avoid distributed password-guessing attacks.
You'd need about 600 IPs to effectively lock out a user, which should be fine?

Copy link

cloudflare-workers-and-pages bot commented Jul 25, 2024

Deploying matrix-authentication-service-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3b89cf8
Status: ✅  Deploy successful!
Preview URL: https://d64cc012.matrix-authentication-service-docs.pages.dev
Branch Preview URL: https://quenting-ratelimits.matrix-authentication-service-docs.pages.dev

View logs

Copy link
Contributor

@reivilibre reivilibre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall this seems right to me!

@@ -650,6 +670,57 @@ mod tests {
assert_eq!(body, old_body);
}

/// Test that password logins are rate limited.
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had no idea this macro was a thing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's nice, it creates a temporary database and run the migrator on it, so each test gets an isolated database

use nonzero_ext::nonzero;
use ulid::Ulid;

const PASSWORD_CHECK_FOR_REQUESTER_QUOTA: Quota = Quota::per_minute(nonzero!(3u32));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really sure either way but 3/min seems a bit harsh, just thinking about e.g. the company's shared office which has a shared IPv4.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do config and tweak those numbers in another PR

impl Default for LimiterInner {
fn default() -> Self {
Self {
password_check_for_requester: RateLimiter::keyed(PASSWORD_CHECK_FOR_REQUESTER_QUOTA),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't remember for sure but I think you want to call retain_recent on these ratelimiters occasionally to perform housekeeping.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I did that in 5b1c9b4

@sandhose sandhose requested a review from reivilibre July 26, 2024 08:36
@sandhose
Copy link
Member Author

@reivilibre if you could glimpse at 5b1c9b4 and retick, that would be great

@sandhose sandhose force-pushed the quenting/ratelimits branch from 5b1c9b4 to 110c695 Compare July 26, 2024 08:58
@sandhose sandhose force-pushed the quenting/ratelimits branch from 110c695 to 3b89cf8 Compare July 26, 2024 11:43
@sandhose sandhose merged commit 4a275fa into main Jul 26, 2024
16 checks passed
@sandhose sandhose deleted the quenting/ratelimits branch July 29, 2024 12:06
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants