MFA Security: Strengths, Weaknesses, and Best Practices
A comprehensive deep dive into multi-factor authentication methods, their security strengths and weaknesses, bypass techniques, and implementation best practices.
The Uber Breach That a Single Tap Could Have Stopped
In September 2022, an attacker breached Uber's internal systems by sending an MFA fatigue attack — bombarding a contractor with push notification requests until the exhausted user finally clicked "Approve." The attacker had already stolen the contractor's password from a dark web marketplace, but the second factor was all that stood between them and Uber's network. MFA would have stopped the attack cold — if it had been implemented with number matching instead of simple push approvals.
Multi-Factor Authentication (MFA) is a security mechanism that requires users to provide two or more verification factors. MFA combines something you know (password), something you have (device, token), and something you are (biometric).
Prerequisites
Before studying MFA security, you should understand:
Authentication Factors
Something You Know (Knowledge)
Something You Have (Possession)
Something You Are (Inherence)
MFA Methods Ranked by Security
1. Hardware Security Keys (Most Secure)
FIDO2/WebAuthn security keys are the gold standard:
// WebAuthn registration example
const publicKeyCredentialCreationOptions = {
challenge: new Uint8Array(32),
rp: { name: "SecureApp", id: "secureapp.com" },
user: {
id: new Uint8Array(16),
name: "user@example.com",
displayName: "User"
},
pubKeyCredParams: [{ alg: -7, type: "public-key" }],
authenticatorSelection: {
authenticatorAttachment: "cross-platform",
residentKey: "required",
userVerification: "required"
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
Security: Excellent — phishing-resistant, cannot be copied or intercepted.
2. TOTP Authenticator Apps (Strong)
Time-based One-Time Passwords (Google Authenticator, Authy, Microsoft Authenticator):
import pyotp
import qrcode
# Generate TOTP secret
secret = pyotp.random_base32()
totp = pyotp.TOTP(secret)
# Generate QR for user setup
uri = totp.provisioning_uri("user@example.com", issuer_name="SecureApp")
qrcode.make(uri)
# Verify code
code = input("Enter 6-digit code: ")
if totp.verify(code, valid_window=1):
print("Valid!")
Security: Strong — codes expire after 30 seconds, but vulnerable to phishing and session interception.
3. Push Notifications (Moderate)
Duo Security, Microsoft Authenticator push, Okta Verify:
Security: Moderate — vulnerable to MFA fatigue attacks where users are bombarded with push notifications until they accept.
4. SMS/Text Message Codes (Weakest MFA)
Security: Weak — vulnerable to SIM swapping, SS7 attacks, and interception.
# SMS-based MFA vulnerabilities:
# 1. SIM swapping — Attacker ports victim's number to their SIM
# 2. SS7 protocol attacks — Intercept SMS messages
# 3. SMS intercept malware — Android malware reads SMS
# 4. Social engineering — Trick user into sharing code
MFA Bypass Techniques
MFA Fatigue
Bombarding users with push notifications until they accept:
# Automated MFA fatigue tool
# Sends repeated push notifications to the victim's phone
# Most users eventually click "Approve" out of frustration
# In 2022, Uber was breached using MFA fatigue against a contractor
# The contractor accepted a push notification after multiple attempts
SIM Swapping
# Steps attackers take:
# 1. Collect target's personal info (OSINT)
# 2. Call target's mobile carrier
# 3. Claim phone was lost/stolen
# 4. Request SIM transfer to attacker's SIM
# 5. Now receives all SMS, including MFA codes
Session Cookie Theft
# After MFA, the server issues a session cookie
# Stealing the cookie bypasses MFA on subsequent requests
# Methods:
# - Malicious browser extension
# - Malware on endpoint
# - Session token in URL
# - Cross-Site Scripting (XSS)
OAuth Token Theft
# MFA often happens during initial login
# OAuth tokens may be reused across sessions
# Stealing a valid OAuth token bypasses MFA entirely
# Token in memory
# Token in browser storage
# Token in mobile app storage
Backup Code Exploitation
# Almost all MFA systems provide backup codes
# Backup codes are often:
# - Stored insecurely (email, cloud storage)
# - Printed and left accessible
# - Captured during account setup
# - Not regenerated after use
Man-in-the-Middle (Evilginx)
# Evilginx-style reverse proxy attack:
# 1. Attacker sets up proxy (e.g., secure-login.company.com)
# 2. Victim enters credentials on fake page
# 3. Proxy forwards to real site
# 4. Victim enters MFA code
# 5. Attacker captures session cookie
# 6. Bypasses all future MFA
Defending MFA
Phishing-Resistant MFA
// WebAuthn with conditional mediation
if (PublicKeyCredential.isConditionalMediationAvailable) {
const credential = await navigator.credentials.get({
publicKey: {
challenge: serverChallenge,
allowCredentials: allowedCredentials,
userVerification: "required"
},
mediation: "conditional"
});
}
Number Matching
# Microsoft Authenticator number matching
# Instead of "Approve sign-in?", user must type the displayed number
# e.g., "Are you trying to sign in? Enter the number: 538"
# Prevents MFA fatigue attacks
# User must actively engage with the prompt
Geographic and Behavioral Anomaly Detection
def evaluate_login_risk(request):
risk_score = 0
# Geographic anomaly
if is_unusual_location(request.ip_address):
risk_score += 30
# Device anomaly
if is_unusual_device(request.user_agent):
risk_score += 20
# Time anomaly
if is_unusual_time(request.timestamp):
risk_score += 15
# Behavioral anomaly
if is_unusual_typing_speed(request.typing_pattern):
risk_score += 25
return risk_score
# High risk = require additional verification
def should_require_mfa(request):
return evaluate_login_risk(request) > 50
MFA Audit and Monitoring
# Audit MFA status in Azure AD
Get-MsolUser -All | Select-Object UserPrincipalName, StrongAuthenticationRequirements
# Check which users have no MFA
Get-MsolUser -All | Where-Object {
$_.StrongAuthenticationRequirements.Count -eq 0
} | Select-Object UserPrincipalName
# Audit MFA method distribution
Get-MsolUser -All | ForEach-Object {
$_.StrongAuthenticationMethods.MethodType
} | Group-Object | Sort-Object Count -Descending
Real-World Examples
Uber Breach (2022): Attacker used MFA fatigue to breach Uber's internal systems. After purchasing a contractor's credentials on the dark web, the attacker sent repeated MFA push notifications until the contractor accepted.
Twitter Hack (2020): Attackers used social engineering to bypass MFA by convincing Twitter employees to provide access through internal tools, demonstrating that MFA does not protect against all attack vectors.
RSA SecurID Breach (2011): The theft of RSA's SecurID seed values rendered their hardware tokens useless, showing that even hardware MFA can be compromised if the underlying secrets are stolen.
Common Mistakes
Using SMS as the primary MFA method: SMS is the weakest MFA and should only be used when no other option exists.
Not having backup methods: If a user loses their phone, they need alternative verification methods.
No MFA recovery process: Poorly designed account recovery can bypass MFA entirely.
Not enforcing MFA for all users: Privileged accounts are often targeted first.
Session cookies that never expire: Long-lived sessions bypass MFA on subsequent requests.
Best Practices
Related Tools
Related Articles
Summary
MFA significantly improves security over passwords alone, but not all MFA methods are equally secure. Hardware security keys (FIDO2/WebAuthn) are the most secure, followed by TOTP authenticator apps. SMS is the weakest MFA and should be avoided. MFA fatigue, SIM swapping, and session cookie theft are common bypass techniques that require additional defenses like number matching and anomaly detection.