New and improved two-factor lockout recovery process
The Recover Accounts Elsewhere feature lets you associate your GitHub account with your Facebook account. This will help us recover your account for certain two-factor authentication lockout scenarios. For example, you may become locked out of your GitHub account because you have lost your phone or U2F key, changed phones without re-enrolling, or have otherwise lost the ability to use your phone or token without a usable backup.
Currently, losing the ability to authenticate with your phone or token requires that you prove account ownership before we can disable two-factor authentication. Proving ownership requires access to a confirmed email address and a valid SSH private key for a given account. This new recovery feature will provide an alternative proof of account ownership that can be used along with these other methods.
How does it work?
Starting on Tuesday January 31st 2017, you can start using this feature but the tl;dr is:
1. Initiate storing a token on the security settings page on GitHub.
2. Confirm that you would like to store the token.
3. Get locked out for any reason.
4. Contact GitHub Support.
5. Initiate the recovery process by logging into Facebook and use the Recover Accounts Elsewhere feature.
At this point, an audit log entry is added signifying a successful recovery. GitHub Support can then use this information as part of a risk-based analysis to decide if proof of account ownership has been established in order to disable two-factor authentication.
No really, how does it work?
The underlying “Delegated Account Recovery” specification was written by Brad Hill. GitHub will act as the first account provider while Facebook will be the first recovery provider. The general recovery flow between Facebook and GitHub is as follows:
- GitHub encrypts a secret value using 256-bit AES-GCM that is associated with an account’s identity in a recovery token object along with other metadata.
- The token is digitally signed by GitHub using secp256r1.
- Facebook stores this token on their servers until needed. This token is not countersigned until a recovery is initiated and is unusable at this stage.
- When a recovery is initiated, Facebook countersigns the token and sends the countersigned token back.
- GitHub verifies the countersigned token using the following rules:
- The countersignature must be valid.
- The countersigned token must have been issued recently.
- The signature of the original, nested token must be valid.
- GitHub looks up a recovery token by a 128 bit randomly generated ID and ensures that token has been confirmed as saved and has not been revoked.
- GitHub decrypts the secret in the original token and uses this to verify the owner of the token.
GitHub only stores the token ID, user ID, and token state. Facebook only stores a token with an encrypted secret that is associated with a Facebook account and does not become valid until it’s used in a recovery. This process helps limit the impact of database dumps and SQL injection vulnerabilities without an additional compromise of the encryption and signing keys.
At no point does GitHub exchange any personally identifiable information with Facebook. Likewise, Facebook does not exchange any personally identifiable data with us.
Binary serialization? Symmetric crypto? Elliptic curve digital signatures? Oh my!
The astute reader will note that the above flow could likely be implemented using an existing standard such as OAuth. OAuth is “the devil we know” and with just a few small tweaks and additional OAuth scopes, a similar process could be implemented.
So why not OAuth? OAuth’s flexibility can be unnecessary and dangerous. OAuth scopes with bearer tokens immediately grant access to functionality. With the new spec, there are no scopes. No different kinds of tokens. No ambiguities. Additionally, tokens are not immediately valid on their own. We aim to do one thing: help people recover accounts in a safer way.
GitHub will be open sourcing a Ruby library soon so that the complicated and dangerous code paths will be abstracted away and we will provide a Ruby reference implementation as a guide. Follow us on Twitter @GitHubSecurity to keep informed as to when we announce it!
No public review? What gives?
While it is true this spec was developed in private with limited exposure, it was done by someone well versed in this area and has been reviewed by numerous experts in the field. To promote public review, GitHub and Facebook are including the specification as part of a joint bug bounty program. Naturally, our implementation of the specification is automatically in scope. Additionally, we will all pay out for bugs in the specification including features we haven’t implemented yet. You can report these bugs directly to the Facebook Bug Bounty.
We are taking a very careful approach to rolling this out. GitHub values the security of our users’ accounts and we believe using this for two-factor authentication recovery is the best first step. In the future, it may replace or complement password resets. Potentially, you may be able to store encrypted secrets with Facebook such as TOTP seeds or two-factor authentication recovery codes. We’re also planning to support reciprocal Facebook account recovery in the near future. At that point, you’ll be able to use your GitHub account to recover your Facebook account, too.
We think this is a great step towards a better account recovery process. Traditional email-based recovery has flaws, transmitting secrets that grant immediate account access through many hops and clients. With this feature we can ease the pain associated with a locked out account in a way that is well defined and protects the security and privacy of our users.