IT Support & Help Desk Fundamentals Module 10 – Accounts, directories and access
Passwords, MFA and passkeys for support
Apply NIST SP 800-63B-4 password rules, rank MFA methods from SMS to passkeys, and help users enrol and recover without weakening accounts.
What you will learn
- Explain authentication, authorisation and the factor types
- Apply NIST SP 800-63B-4 password rules and explain how they differ from older policies
- Rank MFA methods from SMS codes to phishing-resistant passkeys and security keys
- Recover a user's MFA access without weakening the account
Before you start
What you’ll learn · Before you start
What you will learn
- Explain authentication, authorisation and the factor types
- Apply NIST SP 800-63B-4 password rules and explain how they differ from older policies
- Rank MFA methods from SMS codes to phishing-resistant passkeys and security keys
- Recover a user's MFA access without weakening the account
Before you start
On this page
A user calls because their new 11-character password “Jm9!zPq#4Rb” was rejected even though it has uppercase, lowercase, digits and a symbol. The old policy said those were required; the current one asks for at least 15 characters when the password is the only factor. Password rules have changed, and a support technician who explains why earns more trust than one who just recites the error. Learn the rules NIST now publishes and the reasons behind them, rank MFA methods by what each one stops, and recover a user’s access without weakening the account.
Authentication proves identity; MFA mixes factor types
authentication: The process of proving who a user is, usually by providing one or more factors such as a password, a device, or a biometric. answers the question “who are you?” and authorisation: The process of deciding what an authenticated user may do: which resources they can access and which actions they can take. answers “what may you do?” A user signs in (authentication), and then the system decides whether they can read a file, approve a payment or change a setting (authorisation). Mixing the two is a common mistake: a locked-out user has an authentication problem, while a user who can sign in but cannot open a folder has an authorisation problem.
Authentication relies on factors, evidence a user provides to prove their identity. The three types are:
| Factor type | What it is | Examples |
|---|---|---|
| Something you know | A secret the user memorises | Password, PIN, passphrase |
| Something you have | A device or token the user possesses | Phone, security key, smart card |
| Something you are | A biometric the user presents | Fingerprint, face, iris |
Single-factor authentication uses one factor, usually a password. multi-factor authentication (MFA): Authentication that requires at least two independent factors from different types: something you know, something you have, or something you are. (MFA) requires at least two independent factors from different types. A password plus a code from an authenticator app is MFA because the password is something you know and the phone running the app is something you have. Two passwords are not MFA; they are still one factor type.
Two factors, not two steps
A site that asks for a password and then for the same password again is not using MFA. MFA means two different factor types, not two inputs of the same type.
Checkpoint
Check: Factor types and MFA
NIST now asks for length and a blocklist, not complexity rules
The US National Institute of Standards and Technology publishes NIST SP 800-63B: A US federal guideline on digital identity authentication, published by NIST; the current version (SP 800-63B-4) requires longer passwords, blocklist checks, and no composition rules., a guideline many organisations follow. The current revision, SP 800-63B-4, differs sharply from the older rules that many policies and exams still describe.
- Legacy era
Composition rules: uppercase, digit, symbol dropped
Policies required at least one uppercase letter, one digit and one symbol. Users responded with predictable patterns like "Password1!" and wrote passwords down. The rules added friction without adding security.
- Legacy era
Forced rotation every 90 days dropped
Users had to change passwords every 60 to 90 days. Many made the smallest change the rule allowed, such as raising a trailing number by one, so the new password was as easy to guess as the old one.
- Legacy era
Password hints and security questions dropped
Knowledge-based hints like "mother's maiden name" were often guessable from public records or social media. Attackers used them to reset passwords without knowing the original.
- SP 800-63B rev 3
Revision 3 advises against composition rules guidance
Revision 3 said verifiers should not impose composition rules or make users change passwords on a calendar, and shall force a change when there is evidence of compromise. Length matters more than character variety.
- SP 800-63B rev 3
A blocklist check and room for 64 characters guidance
Revision 3 required new passwords to be compared with a list of commonly used, expected or compromised values, and asked verifiers to accept at least 64 characters so that long passphrases fit.
- SP 800-63B-4
Revision 4 turns the advice into "shall not" guidance
Revision 4 says verifiers shall not impose composition rules and shall not require periodic changes. A change is still forced on evidence that the password is compromised.
- SP 800-63B-4
SP 800-63B-4 raises the minimum to 15 characters guidance
A password used as the only factor now needs at least 15 characters; one used with a second factor keeps the minimum of 8. A passphrase of several words picked at random reaches 15 and is easier to remember than a short complex string.
- SP 800-63B-4
The whole password meets the blocklist guidance
Revision 4 keeps the blocklist and says the entire password is compared, not the words inside it. A long passphrase that contains a common word is accepted unless the whole phrase is on the list.
The timeline has 8 events, from Legacy era to SP 800-63B-4.
The main changes in summary:
| Rule | Legacy policy | NIST SP 800-63B-4 |
|---|---|---|
| Minimum length (single factor) | 8 characters | 15 characters |
| Minimum length (with MFA) | 8 characters | 8 characters |
| Maximum length | Often 16 or 20 | At least 64 |
| Composition (uppercase, digit, symbol) | Required | Shall not be imposed |
| Periodic expiration | Every 60–90 days | Only on evidence of compromise |
| Blocklist check | Rare | Required (breached and common passwords) |
| Hints and security questions | Common | Shall not be used |
The logic is straightforward. Composition rules lead to predictable patterns like “Password1!” because users satisfy the rules with minimal effort. Forced expiration invites the same shortcut, a trailing number raised by one at every change, so the guideline asks for a new password only when there is evidence the old one is compromised. Length matters more than complexity. “Jm9!zPq#4Rb” mixes every character type and still misses the 15-character minimum at 11. A randomly generated passphrase, such as “lantern cobalt mango drizzle”, reaches 28 characters that are easier to remember, and its strength comes from the random pick: four words from a list of 7,776 give 7,776⁴, about 3.7 × 10¹⁵ possible phrases. “Four random words” is a rule of thumb and not a guarantee of length: a generator picks again when the result is too short, or the user picks five words to clear 15 characters with room to spare. A phrase printed anywhere, this one included, is the kind of expected value a blocklist holds, so a real passphrase comes from a generator.
Not affiliated
MySmartCoPilot is not affiliated with CompTIA. The exam facts below come from CompTIA’s published exam objectives; the policy comparisons and examples in this lesson are this track’s own.
CompTIA’s A+ Core 2 (220-1202) exam objectives still list complexity and expiration, next to length, among the password considerations of objective 2.7, reflecting what many organisations still enforce. Learn both: what exams and older policies say, and what current NIST guidance requires and why. When a user asks why their complex password was rejected, a technician who can explain the shift—length over complexity, no forced rotation, blocklist checks—gives a better answer than one who only says “the system rejected it.”
#!/usr/bin/env python3
"""NIST SP 800-63B-4 aligned password acceptability checker.
SP 800-63B-4 requires:
- Single-factor passwords: at least 15 characters
- MFA passwords: at least 8 characters
- Verifiers should allow at least 64 characters
- No composition rules (no required symbols, digits, uppercase)
- No periodic changes except on evidence of compromise
- New passwords checked against a blocklist
- No hints or knowledge-based authentication questions
This checker applies the length and blocklist rules.
"""
def acceptable(password: str, context: str, blocklist: set[str]) -> tuple[bool, str]:
"""Check if a password meets NIST SP 800-63B-4 requirements.
Args:
password: The password to check (Unicode string).
context: Either "single_factor" (>= 15 chars) or "mfa" (>= 8 chars).
blocklist: A set of blocked passwords (checked case-insensitively).
Returns:
A tuple of (accepted: bool, reason: str).
"""
# Trim leading and trailing whitespace (NIST allows this)
trimmed = password.strip()
# Count Unicode code points, not bytes
length = len(trimmed)
# Determine the minimum length by context
if context == "single_factor":
min_length = 15
elif context == "mfa":
min_length = 8
else:
return (False, f"Unknown context: {context}")
# Check minimum length
if length < min_length:
return (False, f"Too short: {length} chars, need {min_length} for {context}")
# Check blocklist (case-insensitive)
if trimmed.lower() in blocklist:
return (False, "Blocked: appears in the common-passwords list")
# NIST: verifiers should allow at least 64 characters
# We accept any length >= min_length; no upper limit enforced here
return (True, f"Accepted: {length} chars for {context}")
# A small blocklist for demonstration (a real one has thousands)
BLOCKLIST = {
"password", "123456", "qwerty", "letmein", "welcome",
"admin", "monkey", "dragon", "sunshine", "princess",
"iloveyou", "trustno1", "baseball", "football", "hello",
}
# Original sample passwords (not copied from any list)
SAMPLES = [
# Single-factor tests
("shortpass12345", "single_factor"), # 14 chars - too short
("blueskymorning7", "single_factor"), # 15 chars - accepted
("thunderstormXYZabc", "single_factor"), # 18 chars - accepted
("password", "single_factor"), # 8 chars, blocklisted, too short
("verylongpasswordthatisabsolutelyaccepted", "single_factor"), # 40 chars
# MFA tests
("tiny123", "mfa"), # 7 chars - too short for MFA
("okaylength", "mfa"), # 10 chars - accepted for MFA
("letmein", "mfa"), # 7 chars, blocklisted
("briefmfa", "mfa"), # 8 chars - exactly minimum
# Unicode length tests (code points, not bytes)
("cafénoir☕abc", "mfa"), # 12 code points - accepted
("日本語パスワード安全です", "single_factor"), # 12 code points - too short
("日本語パスワード安全ですよ!", "single_factor"), # 14 code points - too short
]
if __name__ == "__main__":
print("NIST SP 800-63B-4 password policy check")
print("=" * 50)
print()
for pwd, ctx in SAMPLES:
accepted, reason = acceptable(pwd, ctx, BLOCKLIST)
status = "ACCEPT" if accepted else "REJECT"
# Show a truncated display for long passwords
display = pwd if len(pwd) <= 25 else pwd[:22] + "..."
print(f"{status:6} | {ctx:13} | {display:25} | {reason}") Output
NIST SP 800-63B-4 password policy check ================================================== REJECT | single_factor | shortpass12345 | Too short: 14 chars, need 15 for single_factor ACCEPT | single_factor | blueskymorning7 | Accepted: 15 chars for single_factor ACCEPT | single_factor | thunderstormXYZabc | Accepted: 18 chars for single_factor REJECT | single_factor | password | Too short: 8 chars, need 15 for single_factor ACCEPT | single_factor | verylongpasswordthatis... | Accepted: 40 chars for single_factor REJECT | mfa | tiny123 | Too short: 7 chars, need 8 for mfa ACCEPT | mfa | okaylength | Accepted: 10 chars for mfa REJECT | mfa | letmein | Too short: 7 chars, need 8 for mfa ACCEPT | mfa | briefmfa | Accepted: 8 chars for mfa ACCEPT | mfa | cafénoir☕abc | Accepted: 12 chars for mfa REJECT | single_factor | 日本語パスワード安全です | Too short: 12 chars, need 15 for single_factor REJECT | single_factor | 日本語パスワード安全ですよ! | Too short: 14 chars, need 15 for single_factor
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 policy_check.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
The checker applies two rules: minimum length by context (15 for single-factor, 8 for MFA) and a blocklist. It does not require uppercase, digits or symbols, and it counts Unicode code points, not bytes, so a passphrase in any language is measured fairly. The blocklist is compared with the whole password, never with a word inside it, and NIST’s examples of what the list may hold include context-specific words such as the service’s name and the user’s own username.
Pwned Password Checker Check a password against known breaches; only five characters of its hash are sent.Checkpoint
Check: NIST password rules
Only origin-bound factors stop a convincing phishing site
Not all second factors offer the same protection. The table below ranks common MFA methods by phishing resistance, recovery options and user friction:
Answer the questions above: the table then marks what fits your case and says why the rest does not.
| Second factor | Phishing resistance | Recovery when lost | User friction | Per-user cost |
|---|---|---|---|---|
| SMS code How it works: code sent by text to a phone number | Poor none: attacker can read the code if they control the link | Good change the phone number, no hardware needed | Good familiar to users, works on any phone | Good any phone works; the sending service may bill per message |
| Authenticator app How it works: time-based code from an app like Google Authenticator | Poor none: a fake page can relay the code within its 30-second window | Mixed backup codes or re-enroll, secret is lost with the device | Mixed user must open app, read code, type it in time | Good no per-user cost beyond the authenticator app |
| Push notification How it works: approve or deny on a paired app | Mixed some: user sees a prompt, but fatigue attacks succeed | Mixed re-pair the app on a new device, needs identity proof | Good one tap to approve, no code to type | Mixed no hardware; depends on the identity provider's plan |
| Security key How it works: USB or NFC device, such as a YubiKey | Good high: origin binding stops fake sites, no code to steal | Mixed backup key or admin reset, hardware must be replaced | Mixed user must carry and plug in a device | Poor hardware is bought per user, which the other factors avoid |
| Passkey How it works: credential on a phone, computer or key, used after a fingerprint, face or PIN check | Good high: origin bound, no shared secret to intercept | Mixed synced passkeys recover via cloud, device-bound need backup | Good biometric or PIN, no code to type or device to carry | Good built into modern devices, no extra hardware |
How the answers decide
- “Is the account a high-value target for phishing, such as admin, finance or executive?” Yes, high-value target: rules out SMS code and Authenticator app. SMS codes and TOTP can be phished in real time. A high-value account needs a phishing-resistant factor: a security key or a passkey.
- “Is the account a high-value target for phishing, such as admin, finance or executive?” No, standard user and “Does the organisation control the devices, or do users bring their own?” Bring your own device: adds a caveat to Security key. Users may forget or lose a key they carry themselves. Passkeys synced to a personal cloud or push notifications work on devices they already have.
- “Is there budget for hardware keys?” No hardware budget: rules out Security key. Security keys add a per-user hardware cost. Passkeys use built-in hardware, and authenticator apps add no per-user cost.
- “Does the organisation control the devices, or do users bring their own?” Managed devices and “Is there budget for hardware keys?” Yes, hardware budget exists: adds a caveat to SMS code, Authenticator app and Push notification. With managed devices and budget, security keys or device-bound passkeys give the strongest protection and central control.
SMS and voice codes
The weakest second factor. An attacker who controls the phone number—through a SIM swap: A social-engineering attack in which an attacker convinces or bribes a carrier employee to move a victim's phone number to a SIM the attacker controls, intercepting SMS codes. (convincing or bribing a carrier employee to move the number) or by intercepting the message—receives the code. CISA’s Scattered Spider advisory (AA23-320A) describes a group that used SIM swaps, and calls to help desks while posing as employees, to get past MFA.
Authenticator apps (TOTP)
An authenticator app generates a time-based code every 30 seconds using RFC 6238. The shared secret is held by the app and the server from enrolment onwards and never sent again. This is better than SMS because the shared secret does not travel with every sign-in, but the code can still be phished: an attacker who runs a fake sign-in page can relay the code to the real site within its 30-second window.
#!/usr/bin/env python3
"""RFC 6238 TOTP demonstration with test vectors.
TOTP (Time-based One-Time Password) generates a code from:
1. A shared secret known to authenticator and verifier
2. The current time, divided into steps (usually 30 seconds)
This demo reproduces the official test vectors from RFC 6238 Appendix B.
No secrets are transmitted; this is a local computation only.
"""
import hashlib
import hmac
import struct
def hotp(secret: bytes, counter: int, algorithm: str, digits: int = 8) -> str:
"""Generate HOTP code per RFC 4226.
Args:
secret: The shared secret as bytes.
counter: The counter value (for TOTP, this is time / step).
algorithm: Hash algorithm ("sha1", "sha256", or "sha512").
digits: Number of digits in the output code (default 8).
Returns:
The HOTP code as a zero-padded string.
"""
# Pack counter as 8-byte big-endian
counter_bytes = struct.pack(">Q", counter)
# Compute HMAC with the chosen algorithm
if algorithm == "sha1":
mac = hmac.new(secret, counter_bytes, hashlib.sha1).digest()
elif algorithm == "sha256":
mac = hmac.new(secret, counter_bytes, hashlib.sha256).digest()
elif algorithm == "sha512":
mac = hmac.new(secret, counter_bytes, hashlib.sha512).digest()
else:
raise ValueError(f"Unknown algorithm: {algorithm}")
# Dynamic truncation: use last nibble as offset
offset = mac[-1] & 0x0F
# Extract 4 bytes starting at offset, mask top bit
code_int = struct.unpack(">I", mac[offset : offset + 4])[0] & 0x7FFFFFFF
# Reduce to the requested number of digits
code = code_int % (10**digits)
return str(code).zfill(digits)
def totp(secret: bytes, unix_time: int, step: int, algorithm: str, digits: int = 8) -> str:
"""Generate TOTP code per RFC 6238.
Args:
secret: The shared secret as bytes.
unix_time: Unix timestamp (seconds since the Unix epoch).
step: Time step in seconds (usually 30).
algorithm: Hash algorithm ("sha1", "sha256", or "sha512").
digits: Number of digits in the output code.
Returns:
The TOTP code as a zero-padded string.
"""
counter = unix_time // step
return hotp(secret, counter, algorithm, digits)
# RFC 6238 test vectors (Appendix B)
# These test secrets are the ASCII strings "12345678901234567890" repeated/truncated
# to 20, 32, or 64 bytes depending on the hash algorithm.
SECRET_SHA1 = b"12345678901234567890" # 20 bytes for SHA-1
SECRET_SHA256 = b"12345678901234567890123456789012" # 32 bytes for SHA-256
SECRET_SHA512 = b"1234567890123456789012345678901234567890123456789012345678901234" # 64 bytes for SHA-512
# Test times from RFC 6238 Appendix B
TEST_VECTORS = [
# (unix_time, expected_sha1, expected_sha256, expected_sha512)
(59, "94287082", "46119246", "90693936"),
(1111111109, "07081804", "68084774", "25091201"),
(1111111111, "14050471", "67062674", "99943326"),
(1234567890, "89005924", "91819424", "93441116"),
(2000000000, "69279037", "90698825", "38618901"),
(20000000000, "65353130", "77737706", "47863826"),
]
STEP = 30 # Standard 30-second step
if __name__ == "__main__":
print("RFC 6238 TOTP test vectors (8-digit codes, 30-second step)")
print("=" * 72)
print()
print(f"{'Time (Unix)':<14} {'SHA-1':<12} {'SHA-256':<12} {'SHA-512':<12} Status")
print("-" * 72)
all_pass = True
for unix_time, exp_sha1, exp_sha256, exp_sha512 in TEST_VECTORS:
got_sha1 = totp(SECRET_SHA1, unix_time, STEP, "sha1", 8)
got_sha256 = totp(SECRET_SHA256, unix_time, STEP, "sha256", 8)
got_sha512 = totp(SECRET_SHA512, unix_time, STEP, "sha512", 8)
match_sha1 = got_sha1 == exp_sha1
match_sha256 = got_sha256 == exp_sha256
match_sha512 = got_sha512 == exp_sha512
all_match = match_sha1 and match_sha256 and match_sha512
all_pass = all_pass and all_match
status = "PASS" if all_match else "FAIL"
print(f"{unix_time:<14} {got_sha1:<12} {got_sha256:<12} {got_sha512:<12} {status}")
print("-" * 72)
print(f"\nOverall: {'All vectors passed' if all_pass else 'Some vectors failed'}") Output
RFC 6238 TOTP test vectors (8-digit codes, 30-second step) ======================================================================== Time (Unix) SHA-1 SHA-256 SHA-512 Status ------------------------------------------------------------------------ 59 94287082 46119246 90693936 PASS 1111111109 07081804 68084774 25091201 PASS 1111111111 14050471 67062674 99943326 PASS 1234567890 89005924 91819424 93441116 PASS 2000000000 69279037 90698825 38618901 PASS 20000000000 65353130 77737706 47863826 PASS ------------------------------------------------------------------------ Overall: All vectors passed
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 totp_demo.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
The demo computes the test vectors from RFC 6238 Appendix B using only the standard library. The same algorithm runs in Google Authenticator, Microsoft Authenticator and similar apps.
TOTP / HOTP Code Generator Watch a six-digit code change every 30 seconds from one shared key.Push notifications with number matching
A push notification asks the user to approve the sign-in on their paired device. This is faster than typing a code and harder to phish because the user sees the request context (the app, the location). Without number matching, however, MFA fatigue: An attack that sends repeated MFA push notifications until the user approves one out of frustration; also called push bombing. Number matching defeats it. attacks succeed: an attacker triggers repeated prompts until the user taps “Approve” to stop them. Number matching—requiring the user to type into the app the number shown on the sign-in screen—defeats this: the number appears on the screen of whoever started the sign-in, so a user who did not start it never sees the number, and a reflex tap can no longer approve the attacker’s request.
Security keys and passkeys
FIDO2 security key: A physical device, such as a YubiKey, that authenticates using FIDO2 public-key cryptography; phishing-resistant because the credential is bound to the site origin. and passkey: A FIDO2 credential stored on a device or in a cloud keychain, used after the user verifies with a fingerprint, face or device PIN; phishing-resistant because it is bound to the site origin. are phishing-resistant MFA: An MFA method whose credential is cryptographically bound to the site origin, so a fake site cannot request it; examples include passkeys and FIDO2 security keys. because the credential is bound to the site’s origin. A fake site at “examp1e.com” cannot request a passkey for “example.com”; the browser refuses. No code travels that an attacker could intercept. CISA’s phishing-resistant MFA fact sheet recommends these for high-value accounts.
The drawing shows the whole scene; its 7 steps are listed below.
Every step as text
- User starts sign-in. The user enters their username or selects a saved passkey. No password is typed; the browser or OS will handle the credential.
- Server sends a challenge. The server generates a random challenge (a nonce) and sends it to the browser. The challenge is unique to this sign-in attempt, so a signature over it cannot be reused for another one.
- Browser checks the origin. The browser verifies that the request came from the real site. A phishing site at "examp1e.com" cannot trigger a passkey for "example.com" because the credential is bound to the origin.
- Device asks for verification. The device asks the user for verification with a fingerprint, face or device PIN. This proves the user is present and authorises use of the private key.
- Private key signs the challenge. The authenticator signs the challenge with the private key. The private key stays with the user's authenticator; only the signature travels to the server.
- Browser sends the response. The browser sends the signature, the client data (which names the origin and the challenge) and the credential ID back to the server. No secret is transmitted.
- Server verifies the signature. The server looks up the public key it stored at registration and verifies the signature against the challenge. If the signature is valid, the challenge is fresh, and the origin matches, sign-in succeeds.
The server stores only the public key. The private key stays with the user: on the device or security key, or in the cloud keychain that syncs it between the user’s own devices. A breach of the server therefore leaks nothing that lets an attacker sign in as the user. Synced passkeys make recovery easier, because a new phone signed in to the same keychain has them; device-bound passkeys (stored only on one security key or device) are harder to recover but cannot be copied to another device.
Checkpoint
Check: MFA method strength
Safe MFA recovery needs a channel the attacker cannot control
The help desk is itself an attack surface. Scattered Spider actors impersonated employees and called help desks to reset MFA, bypassing the second factor entirely. The fix is a verification step that an attacker cannot fake.
Enrolling MFA
When a user enrols MFA for the first time, they should:
- Sign in from a trusted device and network.
- Complete identity verification (a second channel like a video call, or verification by a manager).
- Register at least two methods so a lost phone does not lock them out.
- Store backup codes in a secure place, not a screenshot.
The technician’s job is to guide the user through the enrolment flow and confirm they have a backup method. Never enrol MFA on behalf of a user by reading their code aloud; that defeats the factor.
Recovering MFA
When a user loses access to their second factor, the recovery process must verify their identity through a channel the attacker cannot control. Put every step a procedure might use to one test: could an attacker who has researched the user do it too?
| Recovery step | Could a prepared attacker do it? | Use it? |
|---|---|---|
| A backup code the user stored at enrolment | No, the code is with the user | Yes |
| A second registered phone or security key | No, the device is with the user | Yes |
| A video call with an ID check against the user’s record | Hard: it needs the face and the document | Yes |
| The manager confirms in person or on a number from the directory | No, the attacker does not pick the channel | Yes |
| A reset link sent to an email address the caller gives | Yes, the caller can give an address they control | No |
| Answers about the user: employee number, manager’s name, phone digits | Yes, all of it can be found | No |
| A caller who sounds sure, urgent or senior | Yes, that is the usual approach | No |
Every “No” row fails for the same reason: a step that an attacker could also complete is not verification, however convincing the caller sounds.
Resetting MFA over the phone
Wrong: “I’ll reset your authenticator app; what’s the code on your screen?” Right: “I’ll send a reset link to your backup email, and your manager will confirm the request before we process it.” The wrong version gives the attacker exactly what they need.
Password managers and passphrases
A password manager stores long, unique passwords so users do not have to memorise them. The one password a user still has to remember is what opens the vault, which is where a passphrase of several random words fits: long enough for the 15-character rule and easy to type.
Passphrase Generator (Diceware) Make a passphrase of random words to open a password manager's vault. Password Strength Checker Compare how long a short complex password and a four-word passphrase would last against guessing.When a user asks which password manager to use, the answer is: any reputable one is better than none. The goal is long, unique passwords for every site, stored encrypted, and opened with one strong passphrase or with a passkey.
Checkpoint
Check: Defensive help-desk practices
Practise: decide which passwords a policy should accept
The starter is a legacy policy: eight characters with an uppercase letter, a digit and a symbol, so it accepts “Jm9!zPq#4Rb” and refuses a long lowercase passphrase. Replace it with the rules of this lesson, plus the context-specific rule from the NIST section: refuse a password that is the user’s own username, compared whole and without regard to case, never searched for inside a longer password. The sample tests fail on the legacy starter and pass once every rule holds.
Exercise · Easy · Python
NIST-aligned password acceptability checker
The starter acceptable(password, context, blocklist, username="") in password_check.py is a legacy policy: at least 8 characters with an uppercase letter, a digit and a symbol. Replace it with a check that meets NIST SP 800-63B-4.
The function receives:
password: a Unicode string (it may contain leading or trailing whitespace, which should be trimmed)context: either"single_factor"(minimum 15 characters) or"mfa"(minimum 8 characters)blocklist: asetof lowercase blocked passwordsusername: the user's own username, when the caller knows it (an empty string otherwise)
The function returns a tuple (accepted, reason):
acceptedisTrueif the password is acceptable,Falseotherwisereasonis a short string explaining the decision
Rules to apply:
- Trim leading and trailing whitespace from the password before checking.
- Count Unicode code points (characters), not bytes. The emoji "☕" is 1 character; "café" is 4.
- If the context is
"single_factor", the minimum length is 15 characters. - If the context is
"mfa", the minimum length is 8 characters. - Refuse any other context.
- Compare the whole trimmed, lowercased password with the blocklist. If it matches an entry, refuse it.
- Refuse a password that equals the username, ignoring case. Compare the whole password: a longer password that only contains the username is not refused by this rule.
- Do not impose composition rules (no requirement for uppercase, digits or symbols).
The sample tests include passwords at the exact minimum lengths, a short complex password, Unicode passphrases, the username in another case and an unknown context.
Starter code · password_check.py
# Check whether a password meets NIST SP 800-63B-4 requirements.
# This starter is the legacy policy the exercise replaces: it wants composition, not length.
def acceptable(password, context, blocklist, username=""):
"""Check if a password is acceptable for the given context.
Args:
password: The password to check (Unicode string).
context: Either "single_factor" (>= 15 chars) or "mfa" (>= 8 chars).
blocklist: A set of blocked passwords, in lowercase.
username: The user's own username, if known; a password equal to it is refused.
Returns:
A tuple of (accepted: bool, reason: str).
"""
has_upper = any(c.isupper() for c in password)
has_digit = any(c.isdigit() for c in password)
has_symbol = any(not c.isalnum() for c in password)
if len(password) < 8:
return (False, "Too short: the legacy policy wants 8 characters")
if not (has_upper and has_digit and has_symbol):
return (False, "Rejected: wants an uppercase letter, a digit and a symbol")
return (True, "Accepted by the legacy policy") The sample tests · test_password_check.py
from password_check import acceptable
BLOCKLIST = {"password", "letmein", "welcome", "admin", "qwerty"}
USER = "Asha.Kumar"
def test_single_factor_minimum():
"""single-factor passwords must be at least 15 characters"""
result, _ = acceptable("shortpassword1", "single_factor", BLOCKLIST, USER)
assert result is False, "14 characters is too short for single_factor"
result, _ = acceptable("fifteencharacte", "single_factor", BLOCKLIST, USER)
assert result is True, "exactly 15 characters is acceptable for single_factor"
def test_mfa_minimum():
"""MFA passwords must be at least 8 characters"""
result, _ = acceptable("short12", "mfa", BLOCKLIST, USER)
assert result is False, "7 characters is too short for mfa"
result, _ = acceptable("eightchr", "mfa", BLOCKLIST, USER)
assert result is True, "exactly 8 characters is acceptable for mfa"
def test_composition_is_not_enough():
"""a short complex password fails the single-factor length rule"""
result, _ = acceptable("Jm9!zPq#4Rb", "single_factor", BLOCKLIST, USER)
assert result is False, "11 characters is too short for single_factor"
def test_unicode_length():
"""length is measured in code points, not bytes"""
# 8 code points, 11 bytes in UTF-8
result, _ = acceptable("café☕abc", "mfa", BLOCKLIST, USER)
assert result is True, "8 Unicode code points is acceptable for mfa"
japanese = "日本語パスワード安全ですよ!" # 14 code points, 42 bytes in UTF-8
result, _ = acceptable(japanese, "single_factor", BLOCKLIST, USER)
assert result is False, "14 code points is too short for single_factor"
def test_blocklist_whole_password_any_case():
"""the whole lowercased password is compared with the blocklist"""
result, _ = acceptable("PASSWORD", "mfa", BLOCKLIST, USER)
assert result is False, "PASSWORD lowercased is on the blocklist"
result, _ = acceptable("LETMEIN!", "mfa", BLOCKLIST, USER)
assert result is True, "letmein! is not an entry of the blocklist"
def test_username_is_refused_whole_not_as_a_substring():
"""a password equal to the username is refused; one that only contains it is not"""
result, _ = acceptable("asha.KUMAR", "mfa", BLOCKLIST, USER)
assert result is False, "the password is the username in another case"
result, _ = acceptable("asha.kumar runs on sunday", "mfa", BLOCKLIST, USER)
assert result is True, "a password that only contains the username is allowed"
def test_unknown_context_is_refused():
"""only the two contexts of the rules are accepted"""
result, _ = acceptable("a long and unusual passphrase", "mfa", BLOCKLIST, USER)
assert result is True, "29 characters is acceptable for mfa"
result, _ = acceptable("a long and unusual passphrase", "sms", BLOCKLIST, USER)
assert result is False, "an unknown context such as sms is refused"
def test_whitespace_trimmed():
"""leading and trailing whitespace is trimmed before checking"""
result, _ = acceptable(" short1 ", "mfa", BLOCKLIST, USER)
assert result is False, "trimmed length of 6 ('short1') is too short for mfa"
result, _ = acceptable(" fifteencharacter ", "single_factor", BLOCKLIST, USER)
assert result is True, "trimmed length of 16 is acceptable" A hint
Delete the composition checks first: none of the rules asks for them. Then trim the password with password.strip() and use len() to count characters; in Python, len() on a string returns the number of Unicode code points, which is what the rules require. Compare the length against 15 or 8 depending on the context, and compare the whole lowercased password with == or in blocklist, never with a search inside it.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Practice that adapts to you
Practise this lesson
9 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions on identity
Interviewers for support roles often start with the call from the opening and then move to work that changes many accounts at once. The warm-up below is that first call. The two cases after it ask you to plan rather than recall: retiring SMS codes for twenty people with mixed phones, and giving two hundred new joiners two independent methods on their first day.
Warm-up
A user asks why their new password was rejected even though it has uppercase, lowercase, digits and a symbol. What do you tell them?
Current password guidance (NIST SP 800-63B-4) forbids composition rules such as requiring uppercase letters, digits and symbols. What it asks for instead is length, at least 15 characters for a password used without MFA, and a check of the whole password against a blocklist of common and breached passwords. A short complex password like “Jm9!zPq#4Rb” is rejected because its 11 characters are under that minimum; the mix of character types does not make up for the missing length. A randomly generated passphrase from a password manager — five short words, or four longer ones — clears the minimum and is easier to remember than a short complex string. I would explain the reason behind the rule, that length matters more than complexity, and suggest a generated passphrase or a password manager.
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Mid to senior
Your company protects every account with SMS codes. Security cites SIM swaps and asks you to retire SMS for the twenty people who handle finance, admin or production access. The twenty have mixed phones: eight iPhones, nine Androids and three basic phones without apps. Plan the switch so no account ever drops below SMS during it.
-
Fresher to mid
You are rolling out passkeys to two hundred new joiners next month. HR asks for the fastest enrolment that still "protects the account". Design the day-one flow that leaves every new joiner with two sign-in methods that cannot be lost together, and no backup secret stored on the laptop being set up.
Flashcards · 7 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
How does authentication differ from authorisation?
Authentication proves who the user is. Authorisation decides what that user may reach and what they may do.
-
What makes a sign-in multi-factor?
At least two independent factors of different types: something you know, something you have and something you are.
-
What does NIST SP 800-63B-4 ask of a password used without MFA?
At least 15 characters and a check of the whole password against a blocklist of common and breached passwords. It forbids composition rules and forced rotation.
-
A new password with upper and lower case, digits and a symbol was rejected. Why can that be right?
Current guidance values length over mixed characters: an 11-character complex password is under the 15-character minimum for a password used without MFA, and the mix does not make up for it. A long, randomly generated passphrase is the better answer.
-
How do SMS codes, TOTP codes and passkeys compare as second factors?
SMS codes are the weakest, because of SIM swaps. TOTP codes are better but can be phished within their time window. Passkeys and security keys stand up to phishing: each credential works only for the origin it was made for.
-
What is MFA fatigue, and what stops it?
A flood of push prompts sent until the user accepts one out of frustration, also called push bombing. Number matching stops it.
-
What makes a help-desk MFA recovery safe?
Checking the person's identity through a channel the attacker cannot control. A code the caller reads aloud, or a reset link sent to a mailbox that may be taken over, verifies nothing.
Key takeaways
- Authentication proves identity; authorisation grants permissions. MFA combines at least two independent factors from different types: something you know, have or are.
- NIST SP 800-63B-4 requires 15-character passwords for single-factor authentication, blocklist checks, and no composition rules or forced rotation. Learn both current guidance and older exam expectations.
- SMS codes are the weakest second factor (SIM swaps). TOTP codes are better but phishable within their window. Passkeys and security keys are phishing-resistant because the credential is bound to the origin.
- Help-desk recovery must verify identity through a channel an attacker cannot control. A code read aloud or a reset link to a compromised email is not verification.
Terms in this lesson
- authentication
- The process of proving who a user is, usually by providing one or more factors such as a password, a device, or a biometric.
- authorisation
- The process of deciding what an authenticated user may do: which resources they can access and which actions they can take.
- MFA fatigue
- An attack that sends repeated MFA push notifications until the user approves one out of frustration; also called push bombing. Number matching defeats it.
- multi-factor authentication (MFA)
- Authentication that requires at least two independent factors from different types: something you know, something you have, or something you are.
- NIST SP 800-63B
- A US federal guideline on digital identity authentication, published by NIST; the current version (SP 800-63B-4) requires longer passwords, blocklist checks, and no composition rules.
- passkey
- A FIDO2 credential stored on a device or in a cloud keychain, used after the user verifies with a fingerprint, face or device PIN; phishing-resistant because it is bound to the site origin.
- phishing-resistant MFA
- An MFA method whose credential is cryptographically bound to the site origin, so a fake site cannot request it; examples include passkeys and FIDO2 security keys.
- security key
- A physical device, such as a YubiKey, that authenticates using FIDO2 public-key cryptography; phishing-resistant because the credential is bound to the site origin.
- SIM swap
- A social-engineering attack in which an attacker convinces or bribes a carrier employee to move a victim's phone number to a SIM the attacker controls, intercepting SMS codes.
References
- NIST SP 800-63B-4: Digital Identity Guidelines — Authentication and Lifecycle Management (NIST)
- NIST SP 800-63B (revision 3): Digital Identity Guidelines — Authentication and Lifecycle Management (NIST)
- RFC 6238: TOTP: Time-Based One-Time Password Algorithm (IETF)
- Passkeys overview (FIDO Alliance)
- Implementing Phishing-Resistant MFA (CISA)
- AA23-320A: Scattered Spider threat advisory (CISA)
- Use number matching in MFA notifications (Microsoft)
- CompTIA A+ Core 2 (220-1202) exam objectives (CompTIA)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress