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

Mandatory 2FA with existing users without 2FA vulnerable to account takeover #11850

Closed
dstufft opened this issue Jul 14, 2022 · 8 comments
Closed
Labels
2FA bug 🐛 needs discussion a product management/policy issue maintainers and users should discuss security Security-related issues and pull requests

Comments

@dstufft
Copy link
Member

dstufft commented Jul 14, 2022

Users are currently able to add a 2FA device to their account and the intention is that in the future, a user account with 2FA added will require using an API token to do uploads (#7265).

In addition to that, projects are able to require 2FA (or may have this requirement applied to them by PyPI) which would mean that users will end up in a situation where they may sometimes require 2FA but not always. Specifically, if a user has not added a 2FA method to their account, but there are projects they are on that requires 2FA, they won't be able to manage that project because they're not logging in with 2FA but they can do other things on their account.. like create API tokens.

So that means that we end up with a gap here, where a user could opt not to add 2FA to their account, be on a project that requires it, then if their account gets compromised that compromised user could create API tokens which are good until revoked, even if someone later adds 2FA, or even add a 2FA method of their own to the account.

We have two distinct cases for requiring 2FA at the project level:

  1. Projects that opt into it on their own.
  2. Projects that are required to have 2FA by PyPI itself.

But in terms of this gap, you can really narrow the question down to just:

How do we handle existing users on a project when they don't have a 2FA method on their account, but one of their projects starts to require it, for any reason?

I took a look at what GitHub does for organizations that toggle require 2FA on, and they have a big call out that enabling mandatory 2FA will boot anyone from the organization that doesn't have 2FA enabled, and thinking through it, I can't think of a good way of implementing mandatory 2FA, without this flaw, without removing all users from the project that don't have 2FA enabled on their account OR locking them out of their account completely.

For (1) above, going into the future we can either do what GitHub does and boot everyone from the project that doesn't have 2FA enabled or we can prevent toggling the required 2FA flag if any user on the project does not have a 2FA method attached to their account.

For (2), I don't really know what the right answer is. During the transitional period it's fine to leave them alone, but eventually to actually get the benefits of mandatory 2FA, they're going to have to either have their account locked out OR they're going to have to be removed from any projects that require 2FA (and that opens up a whole can of worms about what if they're the only person attached to that project). The same is true for any project in group (1) that have enabled mandatory 2FA that have existing users without 2FA attached to their project.

Addition to the above, the toggling of a project from not requiring 2FA to requiring 2FA is not the only avenue for users without 2FA to get attached to a 2FA requiring project. Off the top of my head, I can think of:

  1. User has 2FA, but then removes it.
  2. Project requires 2FA and all attached users have it, but then someone without 2FA is invited to join the project (which includes invites that could possibly have been sent prior to the project requiring 2FA).

Basically, I think to actually implement mandatory 2FA in a way that is safe from account takeover, you cannot have any user associated with that project, through any means, that does not have 2FA enabled on their account.

We're in a transitionary period, so we'll have to manage this process, but at a minimum we should "stop the bleeding" where possible while we figure out how to cope with this requirement (or figure out if I'm wrong!), but going forward we're always going to have the potential to have a project in this same transitional state anytime (2) triggers a new project to transition from not requring to requiring.

@dstufft dstufft added bug 🐛 needs discussion a product management/policy issue maintainers and users should discuss labels Jul 14, 2022
@dstufft
Copy link
Member Author

dstufft commented Jul 14, 2022

To be clear, the basic path of compromise here is:

  1. Project A has User X, who does not have 2FA
  2. Project A changes from not requiring 2FA, to requiring 2FA but User X is left attached to the project (or gets added later).
  3. User X is unable to manage Project A, but they're no longer active on the project or maybe a bot account does all their uploads, or any other number of reasons why this restriction doesn't bother User X, so they avoid adding 2FA to their account.
  4. User X's account is compromised by Attacker M.
  5. Attacker M adds their own 2FA to User X, fulfilling the "has 2FA" requirement for Project A, and is now able to manage Project A.

@woodruffw
Copy link
Member

Enumerating some of the individual items needed to address this:

  • Users should not be allowed to disable 2FA if they belong to one or more projects with mandatory 2FA.
  • Projects that manually enable mandatory 2FA should not be allowed to do so if any of their users do not yet have 2FA enabled.
  • For projects that have mandatory 2FA enabled automatically ("critical" projects):
    • After a sufficient grace period...
    • ...any user who doesn't have 2FA enabled gets marked as "disabled" on the project
    • ...if no users have 2FA enabled, the entire project gets marked as read-only and requires admin intervention
    • Edge case: if all owners are missing 2FA but a maintainer has 2FA, the project also gets marked as read-only (since we can't unilaterally promote a maintainer to an owner, and a project should always have an active owner)

(Let me know if I got any of these wrong!)

@dstufft
Copy link
Member Author

dstufft commented Jul 15, 2022

We probably also need:

  • A way for owners (maybe maintainers too), to see who in the project has 2FA, so they can see who is preventing them from turning on mandatory 2FA (or who might get removed for a critical project).
  • Projects that have mandatory 2FA should not be able to generate invites for a user that doesn't have 2FA enabled, nor should a user be able to receive an invite, disable 2FA and then take that invite. Any existing invites to users without 2FA should be invalidated as part of going to mandatory 2FA (or alternatively, invited users have to be considered as part of the "make sure all users have 2FA before allowing it to be enabled" step.

Conceptually the right way to think about requiring 2FA for a Project (or Organization if we do it there) is not that we need to check at authorization whether a user has 2FA, because that's a mutable property and can change, but rather we need to ensure that no user without 2FA has any sort of permission to do anything, nor can they gain permission without someone with 2FA explicitly granting it to them.

Any sort of ambient authority that's just laying around waiting for that user to take some general action, is authority that isn't meaningfully restricted since an attacker could that that action themselves.

@dstufft
Copy link
Member Author

dstufft commented Jul 23, 2022

An interesting thing here, if you block inviting a user if they don't have 2FA, that lets you use invites to a project as an oracle to determine if a user has 2FA or not.

What GitHub does here is they let you invite users to an organization regardless of their 2FA status but you cannot accept an invite unless you have 2FA enabled. This technically has the same problem above, that any unaccepted invites to a user without 2FA enabled is a possible liability since it's a form of ambient authority that's just waiting for the user to add 2FA to their account to claim it.

However, GitHub tempers this by making invites only valid for 7 days so that ambient authority is limited in time, and since our project invites are limited to valid for 3 days, we could do a similar thing.

@di
Copy link
Member

di commented Jan 2, 2024

Closing now that 2FA is required for all users.

@di di closed this as completed Jan 2, 2024
@dstufft
Copy link
Member Author

dstufft commented Jan 2, 2024

Re-opening this, mandatory 2FA does not solve this unless we invalidate all existing credentials.

@dstufft dstufft reopened this Jan 2, 2024
@dstufft
Copy link
Member Author

dstufft commented Jan 2, 2024

Or rather, the general problem of "there's still ambient authority out there vulnerable to ATO" still exists, it's just no longer specific to projects that choose to require 2FA, it's now all projects on PyPI.

@miketheman
Copy link
Member

In April 2024 all unenrolled users had their email addresses unverified due to an ATO attack. https://blog.pypi.org/posts/2024-04-03-user-account-access/

The credentials themselves haven't been invalidated, but in order to take over an existing account, you'd also have to obtain email account access to perform verification and then enroll in 2FA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2FA bug 🐛 needs discussion a product management/policy issue maintainers and users should discuss security Security-related issues and pull requests
Projects
None yet
Development

No branches or pull requests

4 participants