A stolen password on its own should not get anyone into anything. That is the whole promise of multi-factor authentication, and it holds only when MFA is on everywhere a password is accepted and the second factor is one an attacker cannot easily capture or redirect.
Most businesses have MFA on email and nowhere else, and most of them are using text messages. Both of those gaps are fixable in a week.
Everywhere means everywhere
Attackers do not care which login has MFA. They find the one that does not. Walk through every place a username and password are accepted and confirm MFA is enforced, not just available.
- Microsoft 365 and Entra ID, for every user, including shared mailboxes with a login and service accounts that can sign in interactively.
- The VPN. If the appliance uses local accounts, replace them with RADIUS or SAML against your identity provider so the same MFA policy applies.
- Remote Desktop Gateway, Azure Virtual Desktop and any remote access tool your IT provider uses to reach your machines.
- The firewall, switch and hypervisor management consoles. Local admin logins on infrastructure rarely have MFA and are exactly what an attacker on the LAN wants.
- Backup consoles, the password manager, the domain registrar, DNS, the payment processor and the bank. Losing DNS or the registrar is as bad as losing the file server.
Ranking the methods
Not all second factors are equal. The question to ask about each is: if the user is on a fake login page that relays everything to the real one in real time, does this factor still stop the attacker? Only the top of the list passes that test.
- FIDO2 security keys and passkeys (YubiKey, Windows Hello for Business, platform passkeys). The key checks the site's real origin, so a lookalike page cannot complete the login. Phishing resistant.
- Authenticator app with number matching. The user must type the number shown on the login screen into the app. Stops push fatigue, but a real-time relay can still pass the number through.
- Authenticator app with time-based codes (TOTP). Works offline, no push to spam, but a code typed into a fake page is a code the attacker can use for the next thirty seconds.
- Push notification without number matching. Attackers send dozens until someone taps approve. Disable this.
- SMS and voice call. The code travels over a network you do not control, to a phone number a carrier employee can move to a new SIM. Last resort only.
What is wrong with SMS specifically
Text message codes fail in three separate ways. SIM swapping: an attacker convinces or bribes a carrier to move your number to their SIM, and every code arrives on their phone. Interception: the SS7 signaling network that routes texts was designed decades ago without authentication and has been abused to redirect messages. And plain phishing: a code typed into a fake page is handed straight to the attacker, exactly like a TOTP code.
SMS also creates a dependency on a phone number, which is a thing people change, lose and share. When a user gets a new number and forgets to update it, the help desk resets MFA over the phone, and now your MFA is only as strong as the help desk's identity check.
- In Entra ID, disable SMS and voice as methods: Entra admin center > Protection > Authentication methods > Policies. Turn off SMS and Voice call, enable Microsoft Authenticator with number matching and FIDO2.
- Give a hardware key to every global admin, finance user and executive. Register two keys per person so a lost key does not become a help desk reset.
Enforce it with Conditional Access, not user settings
Per-user MFA in Microsoft 365 is a legacy setting. It cannot express 'require a phishing-resistant method for admins' or 'block logins from countries we do not operate in'. Conditional Access can, and it is included in Microsoft 365 Business Premium and Entra ID P1.
Build a small set of policies and test each in report-only mode before turning it on. Keep one break-glass account excluded from every policy, with a very long password stored offline and alerting on any sign-in.
- Require MFA for all users, all cloud apps. Exclude only the break-glass account.
- Require phishing-resistant MFA for directory roles (Global Administrator, Exchange Administrator, and so on) using an authentication strength.
- Block legacy authentication. This shuts the door on IMAP and SMTP basic auth, which bypass MFA entirely.
- Block sign-ins from countries you do not do business with, using a Named Location.
- Require a compliant or hybrid-joined device for access to email and SharePoint if you manage devices with Intune.
# Check who still has per-user MFA and no Conditional Access coverage
Connect-MgGraph -Scopes 'UserAuthenticationMethod.Read.All','User.Read.All'
Get-MgUser -All -Property UserPrincipalName | ForEach-Object {
$m = Get-MgUserAuthenticationMethod -UserId $_.UserPrincipalName
[pscustomobject]@{ User = $_.UserPrincipalName; Methods = ($m.AdditionalProperties['@odata.type'] -join ',') }
}Frequently asked questions
Our users push back on installing an app on personal phones. What then?
Hardware keys solve it. A FIDO2 key costs less than an hour of help desk time, plugs into any laptop, and puts nothing on the phone. For desk-bound staff, Windows Hello for Business on the company PC is another zero-phone option.
Is MFA on email enough if the VPN is behind the firewall?
No. The VPN is the front door to the LAN and is exposed to the internet by design. A password reused between email and the VPN is the most common way an email compromise turns into ransomware. Put MFA on both.
What about service accounts and scripts?
Move them to methods that do not use passwords at all: managed identities in Azure, certificate authentication for app registrations, and group Managed Service Accounts on-premises. Any account that must keep a password should be blocked from interactive sign-in by Conditional Access.
Takeaway
Turn MFA on for every login, not just email, and move the second factor up the list: keys for admins and finance, number-matching app for everyone else, SMS switched off. Enforce it with Conditional Access so the policy is yours, not the user's. If you want a hand building the policy set and a break-glass procedure, RackLedge does this as a fixed-scope project.