Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add exponential backoff rate limit to endpoints using mfa #2078

Merged
merged 2 commits into from
Aug 2, 2019

Conversation

sonalkr132
Copy link
Member

@sonalkr132 sonalkr132 commented Aug 1, 2019

Exponential backoff was needed as with 100 req/10 min limit used in
other endpoints would have been inefficient against brute force of
mfa code.
30 sec window would have had probability of 1/10000 (1 - (1 - p)^n, where p = 10^-6 and n = 100)
for successfully guessing the key at least once if limits were 100 req/10 min.
Using binomial distribution, a HO reporter calculcated that after
6932 trials, he would have had more than 50% chance of successfully
guessing the key at least once.
Limits used in this change would allow 4 trails per week and total
of 33 years for 6932 trials.

"/api/v1/gems/yank", # gem yank
"/api/v1/gems" # gem push
]
add_owner_regex = Regexp.new("\/api\/v1\/gems\/\\w+\/owners")
Copy link
Contributor

Choose a reason for hiding this comment

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

The \w (word character [a-zA-Z0-9_]) in the add_owner_regex might be a bit too strict. Here's the route:

POST
/api/v1/gems/:rubygem_id/owners(.:format)
api/v1/owners#create {:format=>/json|yaml/, :rubygem_id=>/[A-Za-z0-9\.\-_]+?/}

The pattern for rubygem_id is a bit more relaxed than \w+. Paths with rubygem_id values containing ., - would bypass the throttle.

Consider using Rails.application.routes.recognize_path(req.path) to reuse its pattern matching here to prevent this category of issues.

recognize_path returns the controller and action for matching and is less brittle than duplicating and matching on route patterns.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks @eliotsykes 💯
I have updated it to use recognize_path.

@eliotsykes
Copy link
Contributor

What do you think about throttling closer to the OTP verification step? (in User#verify_digit_otp or one of the other verification methods perhaps).

Its throttle key could include the user's id to protect against attacks on a single user that are spread across multiple IPs.

Exponential backoff was needed as with 100 req/10 min limit used in
other endpoints would have been inefficient against brute force of
mfa code.
30 sec window would have had probability of 1/10000 (1 - (1 - p)^n, where p = 10^-6 and n = 100)
for successfully guessing the key *at least once* if limits were 100 req/10 min.
Using binomial distribution, a HO reporter calculcated that after
6932 trials, he would have had more than 50% chance of successfully
guessing the key at least once.
Limits used in this change would allow 4 trails per week and total
of 33 years for 6932 trials.
@sonalkr132 sonalkr132 force-pushed the mfa-rate-limit branch 2 times, most recently from d238190 to 48dcecf Compare August 2, 2019 17:57
@sonalkr132
Copy link
Member Author

throttling closer to the OTP verification step?
throttle key could include the user's id

I would prefer to keep all throttling logic in rack attack initializer, which doesn't mean we can't throttle on per user basis. You have already noticed the use of req.params['password']['email'].presence.
API key from Auth header or params is a good contender. I would prefer to address it in a separate PR. Feel free to open an issue for this or even better send a PR 😉

regex matching was prone to errors/loopholes.
@sonalkr132 sonalkr132 merged commit 15eab6b into rubygems:master Aug 2, 2019
@sonalkr132 sonalkr132 deleted the mfa-rate-limit branch August 2, 2019 18:19
@rubygems-deployer rubygems-deployer temporarily deployed to staging August 2, 2019 18:29 Inactive
@sonalkr132 sonalkr132 temporarily deployed to production August 2, 2019 18:43 Inactive
sonalkr132 added a commit to sonalkr132/rubygems.org that referenced this pull request Apr 25, 2020
sonalkr132 added a commit to sonalkr132/rubygems.org that referenced this pull request Apr 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants