The victim's computer is infected with malware, and the victim is entering a TOTP code into their compromised computer in order to publish a package. As soon as a keylogger sees the user enter a TOTP code it is compromised. Malware with a keylogger can steal it and use it to publish a package, potentially before a victim can even hit enter (or it can block/delay the user from hitting enter), meaning even if your TOTP system has replay protection the malware can still use the code first. Entering a TOTP code incorrectly is a common occurrence, so the malware can potentially get many codes by ensuring the user receives an error for an incorrect code so they enter another correct one which can also be stolen.
This is the tricky part about trying to defend against the threat of "victim's computer is infected with malware". It's something of a disaster scenario. However, requiring 2FA at the time a package is published is still useful because it means the token on the victim's computer isn't immediately exploitable, which is definitely a win.
(RE: Where to store TOTP seeds)
Right now crates.io relies entirely on GitHub as an IdP. There are no long-term authentication credentials and the current tokens can always be reset by OAuthing to GitHub.
Introducing another authentication factor changes that. If crates.io itself (i.e. the conduit app) is going to store these, it will be taking on a brand new responsibility it never had before: managing end-user identity credentials. Now there needs to be an entire provisioning workflow for TOTP, along with an account recovery mechanism for it (e.g. "recovery codes") in the event the TOTP seed is lost.
There are various other IdP/2FA-as-a-service options for managing TOTP credentials. They are mostly commercial products. The ones I like are aimed at enterprise use cases and probably not particularly applicable. I imagine the main criteria here for the Rust Project would be secure, reliable, and free, but where GitHub as an IdP for crates.io was something of a no brainer, using a vendor for this particular solution is much less clear cut.
crates.io presently issues long-lived tokens suitable for use in automations/services or directly by humans. This could potentially supplemented by a workflow which issues short lived (e.g. 24h) tokens to humans, in conjunction with some UX improvements to the authentication workflow.
Right now that looks like:
- Cargo prompts you to go to crates.io when you
cargo publish
- crates.io gives you a UI for creating a new token
- Copy and paste token from crates.io into the cargo CLI tool
I'd suggest an authentication workflow that's identical to the gcloud
tool:
Autodetect if the user is in a desktop environment or a remote shell. If the user is in a desktop environment, use something like the open crate to launch a web browser to complete the existing GitHub-based authentication workflow to crates.io, except provisioning a short-lived credential. Upon completion this can e.g. hit a localhost service with the new credential and install it completely automatically.
If the user is not running on a desktop environment or the browser is not otherwise open, display a URL the user can reach to complete the auth workflow. The CLI tool can poll for success, so upon completion of the auth workflow the user is no longer required to manually copy/paste the token.
The main advantages of browser-based workflows over e.g. entering a TOTP code into a shell are that they can leverage much stronger 2FA methods than TOTP, namely U2F or WebAuthN. These methods also generally provide a better experience: hitting a button is easier than transcribing a code. The devices also identify themselves with public key cryptography, making it easy to have multiple devices enrolled.
All that said, when we talk about crates.io publishers taking an extra authentication step to publish a crate, I think it's important to consider what that step actually accomplishes. I think a better thing that step could accomplish is unlocking a digital signature key used to sign a package. That key could be kept in any number of places: a password encrypted file, a Yubikey, a TPM, or something like the Apple T1 chip connected to the TouchBar. Using additional authentication to protect a signature key means you don't just get better authentication to crates.io, but you get authentication which any user of a crate can easily verify.
I think when we talk about changing the cargo publish
experience, signing crates is what we should really be looking towards.