Comment by archi42
1 year ago
The foolproof way is to not send codes as a 2FA (be it mail, SMS or whatever). There is always a risk that the user fails to verify where they're putting that code. Instead use something that verifies the domain without relying on the user, e.g. U2F or passkeys.
In that case the user needs to be fooled to sent the physical device or passkey-app-backup to the attacker. This is much more suspicious and needs a much worse fool than someone entering a code after they already entered their user+password.
If you know that the user uses the same browser to open links sent via mail as they use for their login: For the 2FA step, set a cookie with some unique value on your login domain and sent the user a mail with a link. Opening the link only finishes the login and starts a valid session if that unique cookie is present. This makes it harder for an attacker, since they need to inject that cookie into the victims browser, which means they need to find an XSS-style exploit. Of course you then want to reduce the attack surface by putting the login function on a subdomain of its own.
And obviously this fails if the user is about to login e.g. on their personal computer and then tries to verify the session on their company phone. This can be good or bad, depending on the scenario.
TBF, I wish some companies would use even that basic code-by-whatever 2FA. I've seen cases which have like 5 different domains, all with various logins that customers and employees use. Want to phish them? Just register another domain that looks similar enough to the others and sent some mails. But then there are still services limiting the password length to something like 16, so I think we will still have plenty of work...
Passkeys are cool, but not widely deployed yet. Also, there's currently no way to express "give X identity Y access on Z server", unless X identity already has a passkey set up with the server. This is a non starter for decentralized networks with lots of federated and self-hosted servers. This use case is trivial with email.