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 privacy pass/trusttoken hidden captcha support to rate limit signups #3518

Open
mercedesb opened this issue Mar 2, 2023 · 6 comments · May be fixed by #3519
Open

Add privacy pass/trusttoken hidden captcha support to rate limit signups #3518

mercedesb opened this issue Mar 2, 2023 · 6 comments · May be fixed by #3519

Comments

@mercedesb
Copy link
Contributor

Initial request

Captcha fall back
Login a bunch of times or sign up a bunch of times, NEVER the first time.

Rate limiting and rate tracking. Rails app. Rack-attack maybe?

Approved product design

Overview of Purpose

Rubygems.org wants to reduce (and prevent if possible) bot activity around signup and login. Captchas are a common way to reduce activity, but can also be annoying and repetitive. We’d like to use Privacy Pass to get the same security with a smoother user experience then Captcha, although it doesn’t completely replace Captchas.

Current State

We currently throttle login attempts to 100 per 10 minutes. We also limit signup requests by IP address to 100 per per 10 minutes. Those are generic limits, which also apply to most actions taken on the website, and we want to reduce the rate limit on logins and signups to something below those current limits, as well as allowing those limits to be adjusted separately. We also want to add a captcha to be solved if you want to sign up for more than one account.

Desired State

Implement protection on the Login and Signup pages as a cascading fallback from Privacy Pass -> Regular Captcha -> Hard Rate Limit.

  • 1 signup allowed per IP per 1 hour without privacy pass or captcha
  • 50 signups allowed per IP per 1 hour with a privacy pass or captcha (eg a class of students)
  • 3 login attempts allowed per account per 1 hour **without **privacy pass or captcha
  • 15 login attempts allowed per account per 1 hour with privacy pass or captcha

Successful logins do not increment the login attempt counter, only failures do.

Prerequisite Questions

  1. Choose which Privacy Pass issuers will be used. According to the IETF proposal for privacy pass, a site with the user base of Rubygems.org (~1.5M concurrently active) should not use MORE THAN 3 issuers. The most obvious choices are: Cloudflare and Fastly are both issuers, and Chrome/Google also appears to be an issuer. We don’t have to choose any of these (although Rubygems.org already has a relationship with Fastly so I don’t know why we WOULDN’T use them as one), but if not those three, then we need to identify other issuers and make the case for why we should use them.
  2. Select Captcha Provider/Implementation. Because not all users will have Privacy Pass tokens or be willing/able to engage in getting them, we need to have a standard captcha fallback so real people aren’t blocked from using the site. Rubygems.org doesn’t currently implement captchas anywhere.
  3. Select Rate Limiting Solution/Implementation. Rubygems.org currently does have some rate limiting implemented via rack-attack. Obviously, reusing the same tools we already have implemented is always the preference IF they can support the currently needed use case. Let’s confirm rack attack can support the use case flows listed below for Login and Signup.

Acceptance Criteria

  1. Implement Privacy Pass with no more than 3 accepted issuers for the login and signup pages. (See code implementation walkthrough below for an idea of steps this will take!). If we have a Privacy Pass, we should be okay allowing multiple signup attempts and multiple login attempts on the assumption (at least for now) that a human is doing those things.
  2. Implement captcha fallback, requiring a user to solve a captcha if they don’t have a privacy pass:
    1. Captcha required for signups number 2-50 from a single IP in 1 hour (if no privacy pass)
    2. Captcha required for login attempts 4-15 for a single account in 1 hour (if no privacy pass)
  3. Implement/Update rate limiting to enforce hard rate limits in regardless of privacy pass/captcha activity.
    1. From a single IP address, no more than 50 signup attempts in 1 hour
    2. For a single user account, no more than 15 login attempts per 1 hour
    3. Note that we’ve decided to go with the above numbers to start with but we don’t really know what is correct from a user experience perspective here. SO! Please organize the code in a way that makes it easy to find and change these numbers in the future. The current rack-attack code is a good example of keeping the parameters right up front and together where you can easily find them and know you are changing the correct number.
  4. None of the above should prevent someone from being able to navigate to or interact with the login or signup pages – it should only prevent success on submission of the form.

Relevant Links

Code Walkthrough of how to implement privacy pass on a Server

SImplified Explanation of Privacy Pass and Google’s API for it

IETF Proposal (don’t feel like you have to read this unless these kind of proposals are helpful to you to getting your bearings on a project, or you just enjoy reading internet protocol proposals. It’s dense and bureaucratic..)

Relevant Code

Current Rate Limiting:

Designs

Flows

Flow 1: Signup

Start: Navigates to Signup Page

1.a Try Privacy Pass challenge
  • Can't pass Privacy Pass?
  • Then check “captchaless” rate limit
  • If over “captchaless” rate limit
  • Then show visual captcha
  • Can’t pass visual captcha?
  • Show error and don’t allow signup
1.b Passes Privacy Pass?
  • Don’t show captcha and check hard rate limit
  • Hard rate limit ok?
  • Allow signup
  • Hard rate limit exceeded?
  • Show error and don’t allow signup
1.c Passess Captcha?
  • Check hard rate limit
  • Hard rate limit ok?
  • Allow signup
1.d Hard rate limit exceeded?
  • Show error and don’t allow signup

Flow 2: Login

Start: Navigates to Login Page

1.a Try Privacy Pass challenge
  • Can't pass Privacy Pass?
  • Then check “captchaless” rate limit
  • If over “captchaless” rate limit
  • Then show visual captcha
  • Can’t pass visual captcha?
  • Show error and don’t allow login
1.b Passes Privacy Pass?
  • Don’t show captcha and Check rate limit
  • Rate limit ok?
  • Allow login
  • Rate limit exceeded?
  • Show error and don’t allow login
1.c Passess Captcha?
  • Check rate limit
  • Rate limit ok?
  • Allow login
  • Rate limit exceeded?
  • Show error and don’t allow login
@mercedesb mercedesb changed the title Epic: add privacypass/trusttoken hidden captcha support to rate limit signups Add privacy pass/trusttoken hidden captcha support to rate limit signups Mar 2, 2023
@simi
Copy link
Member

simi commented Mar 2, 2023

What about to turn this into RFC 🤔 ?

@indirect
Copy link
Member

indirect commented Mar 2, 2023

It's my fault this isn't an RFC--it seemed too small of a feature to me. Summarized all the way down, here is the idea:

Today, sign up and sign in have the same rate limits as every other action on the site. As more attackers create accounts to upload malware gems, we should set lower rate limits for guessing passwords and for creating new accounts.

I propose that we fight bot and malicious traffic with minimal user impact by combining rate limits with captchas (and with PrivacyPass). In short, you can sign up (or log in), as today with no captcha. But to sign up many accounts from the same IP, or try several passwords for an account, you need to pass a captcha for each attempt. If available, we accept PrivacyPass to skip the captcha, since that is equivalent "human verification", to further reduce user impact.

@jchestershopify
Copy link
Contributor

Is there any interaction with our WebAuthn work?

@mercedesb
Copy link
Contributor Author

As far as I understand the proposal there's no interaction between the two just an added layer of security up front (@indirect correct me if I'm wrong)

@rubyFeedback
Copy link

rubyFeedback commented Mar 7, 2023

I propose that we fight bot and malicious traffic with minimal user impact by combining rate limits with captchas

I understand that rationale, but often users of a system may still be impacted negatively. For instance, in captchas I often guess incorrectly (in particular when I have to analyse a fragmented picture and miss on some tiles).

I am still motivated to try and solve something, but if I fail, say, 2 or 3 times then I just vanish and don't come back to such websites. It's simply not worth the hassle and additional time investment compared to a system without such anti-user feature.

@indirect
Copy link
Member

indirect commented Mar 7, 2023

Did you catch the part where we won't even show anyone captchas unless they are trying to sign up multiple times from the same IP address within a single brief window? We don't want to solve captchas any more than you do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants