امنیت، هویت، استقرار و تابآوری · فصل ۱ — Threat Model، Access و Session · 82
TOTP and Recovery Codes
Implement a bounded synthetic TOTP verification flow against known test data, define attempt/time-window policy, and design single-use recovery codes whose issuance, storage, use and regeneration are auditable. میتواند برای «TOTP و Recovery Codes» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
Lesson summary
Implement a bounded synthetic TOTP verification flow against known test data, define attempt/time-window policy, and design single-use recovery codes whose issuance, storage, use and regeneration are auditable.
میتواند برای «TOTP و Recovery Codes» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
This lesson produces
میتواند برای «TOTP و Recovery Codes» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
Who it is for
Foundation
Worked baseline, explicit evidence table, local fixture and one guided failure probe.
Repair
Reduce to one broken contract/protocol assumption, observe it, repair it, then restore the full case.
Experienced
Compress introductory syntax; require independent compatibility/reliability decision, negative evidence and residual-limit statement.
Prerequisites
Bounded outcome
By the end of this lesson, you can verify TOTP behavior in a fully local synthetic fixture using standard test data, make time-step, verification-window, and attempt-limit policy explicit, and prove a single-use recovery-code lifecycle whose use, reuse rejection, regeneration, and revocation are observable. The required artifact is MFA Recovery Control Record v1.
This is not proof of production security. The lab uses no real account, real seed, real recovery secret, external target, or production runtime.
Why this is easy to get wrong
TOTP looks like a short number, but its security model depends on a long-lived shared seed, compatible time-step context, a bounded acceptance window, and controlled verification attempts. A recovery code is not an unimportant exception: it is an alternate path to account authority. If it is reusable, weakly stored, or regenerated without revoking the old set, it can undercut the MFA boundary.
Mental model
Separate four concerns:
- TOTP seed — long-lived secret material shared by authenticator and verifier; it is distinct from the displayed OTP.
- Time moving factor — Unix time is mapped to a counter; prover and verifier must agree on time-step and algorithm context.
- Verification policy — generation is not enough; acceptance window, practical lifetime, attempt limit, and replay behavior need explicit policy.
- Recovery path — a recovery code is an alternate authentication secret; successful use consumes it, and regeneration revokes the prior set.
TOTP foundation
RFC 6238 defines TOTP as the time-based variant of HOTP. This fixture uses RFC test vectors so the learner can verify a local implementation without any external service. A vector proves algorithm behavior only within that declared boundary; it does not decide production policy.
Time-step and verification window
The fixture uses a 30-second time-step. The verification window says how many adjacent counters are acceptable. A wider window may tolerate more clock drift, but it also broadens acceptance. Window size is therefore a recorded policy decision, not an unlimited troubleshooting knob.
Attempt limits
A short code has a limited search space, so the verifier must not accept unlimited guesses. The synthetic policy uses max_attempts=3 and visibly rejects attempts after the bound. That number is not declared universal; the competency is making the policy explicit and auditable.
Secret boundary
The TOTP seed is different from the short OTP. The lab uses the public RFC test secret only as synthetic test data. A real raw seed does not belong in the evidence record. Hashing a short OTP also does not provide password-like offline brute-force resistance because the code space is small.
Recovery codes
In this lesson model:
- synthetic plaintext codes are returned once at issuance; stored state keeps digests only;
- each code can authorize recovery once;
- reusing the same code is rejected;
- regeneration creates a replacement set and revokes all previous-set codes;
- use and regeneration events are recorded.
Positive and negative evidence
A happy path is insufficient. Evidence must include:
- a known RFC vector passes;
- a TOTP outside the declared window is rejected;
- the attempt limit is observable;
- one recovery code succeeds once;
- reuse of that code fails;
- codes from the old set fail after regeneration;
- residual risk is separated from direct observation.
Negative Evidence
Negative evidence is retained, not erased. If you deliberately widen the window or reuse a consumed recovery code, the rejection/trade-off evidence remains beside the positive path. The bounded decision must use both.
MFA Recovery Control Record v1
Record these fields for each factor/recovery item: Factor/Recovery Item, Secret Material, Lifetime or Window, Attempt Policy, Storage Boundary, Successful Use Effect, Reuse Expected, Regeneration Effect, Evidence, and Residual Recovery Risk.
Worked example 1 — RFC vector
At Unix timestamp 59, the SHA-1 8-digit RFC vector is 94287082. Passing this demonstrates algorithm parity for that test case only.
Worked example 2 — window mutation
Start from the bounded window, widen it deliberately, and record the changed security/usability trade-off. Authentication success alone is not justification.
Worked example 3 — recovery reuse
Consume one synthetic code successfully. Reusing the same code must return RECOVERY_CODE_REUSED_OR_INVALID. A second success would violate the lifecycle invariant.
Worked example 4 — regeneration
Keep one old code, regenerate the set, then try the old code. It must fail and the event log must contain RECOVERY_SET_REGENERATED.
Failure modes
- exposing or logging a real seed;
- unbounded window changes;
- missing attempt control;
- reusable recovery codes;
- regeneration without old-set revocation;
- treating TOTP as phishing-resistant in the same way as WebAuthn;
- turning contextual guidance into universal product requirements.
Evidence workflow: prediction to decision
Before each probe, write the expected result. Then record the observed result separately and reference a concrete status/event in the Evidence field. Only after that should you write an inference. This separation matters: “the code was accepted” is an observation; “this policy is sufficient for our threat model” is a contextual judgment.
A reproducible workflow for this lesson is:
- Run the baseline policy unchanged.
- Validate the RFC vectors to detect an algorithm mismatch.
- Verify one valid TOTP under the bounded window and retain the accepted counter evidence.
- Reuse that counter and retain replay rejection evidence.
- Submit invalid values until the attempt boundary becomes visible.
- Consume one recovery code and then reuse that same code.
- Regenerate the recovery set and try an unused code from the prior generation.
- State residual risk, including that recovery remains an alternate authority path and this local model does not prove a real identity-proofing process.
Algorithm correctness versus security policy
This lesson deliberately separates two questions. First: does the TOTP implementation match known algorithm test data? RFC vectors can answer that bounded question. Second: what window, attempt policy, and recovery lifecycle are appropriate for a particular system? That depends on threat model, context, usability, and other requirements. Passing the first question does not prove the second.
The same distinction applies to recovery codes. Correct digest lookup and single-use behavior in a fixture demonstrate a local invariant. They do not prove that a real issuance or identity-recovery process is secure.
Storage boundary and log discipline
Evidence needs enough detail for a decision without collecting real secrets. For TOTP, record fixture identity, algorithm, digits, time-step, window, observed counter/result, and status; a real raw seed is unnecessary. For recovery codes, record generation, consume result, and lifecycle event without copying plaintext codes into the report. Synthetic values exist only to make the local lifecycle observable.
Replay and the meaning of one-time
Algorithmically, a TOTP value can remain the same within a time-step. If a verifier keeps no consumption state, the value may be accepted again during that window. This fixture models replay protection with consumed counters so the learner can distinguish “time-based” from “one-time enforcement.” A production design may manage state differently, but expected replay behavior still needs to be explicit.
Concurrency boundary
A real system may receive two simultaneous requests carrying the same OTP or recovery code. This single-process fixture does not simulate production races, so the evidence record retains that limitation as residual risk. The expected invariant remains clear: a single recovery code must not create two independent authority grants, and a concurrent production implementation needs atomic consumption semantics.
Experienced bridge
An experienced learner does not need to hand-code TOTP in a real product. A vetted library can own the primitive, but it does not remove the evidence requirements: verification window, attempt behavior, secret boundary, replay expectation, recovery single-use, and regeneration/revocation must remain inspectable. Higher-level abstraction must not erase the security contract.
Alternatives and trade-offs
Passkey/WebAuthn can provide phishing resistance properties different from TOTP, but changing the primary factor does not automatically eliminate recovery governance. SMS or email OTP are also not equivalent to TOTP merely because they contain one-time codes; their trust dependencies differ. This lesson does not attempt a full product comparison. It requires factor and recovery paths to be modeled separately without unsupported equivalence claims.
Evidence completeness gate
For this lesson, a complete record includes at least one positive path, one negative path, an attempt/replay boundary, recovery reuse rejection, regeneration/revocation evidence, and an independent transfer decision. Removing one of those cannot be compensated for by a green happy path.
Transfer
A synthetic operator moves from TOTP-primary MFA to passkey-primary authentication while retaining emergency recovery codes. Decide which recovery lifecycle controls still apply without claiming that the authentication factors provide equivalent assurance. Base the decision on observed recovery evidence.
Non-goals
We do not claim that TOTP is WebAuthn-like phishing resistance, that hashing a short OTP substitutes for seed protection, that recovery codes may be reusable, or that recovery can silently weaken normal authentication.
Assessment
The final work covers retrieval, application, diagnosis, decision, and transfer. Blocking evidence includes running the fixture, preserving negative evidence, and completing the changed-context task independently. AI may suggest defensive probes or organize observations, but may not invent evidence or make the accountable residual-risk decision.
Sources and freshness
The frozen source boundary is exactly RFC6238, OWASP-MFA, and NIST-800-63-4. A current check on 2026-09-16 remained inside this boundary; the next frozen review due date is 2026-10-02. No new authority was added.
Assessment
There is no answer key in this lesson pack; answer it yourself and mark honestly. "Needs review" sends the lesson to your review queue.
SEC-005-S1 retrieval
State the bounded rule for TOTP verification and one non-goal.
SEC-005-S2 application
Run the local fixture and capture positive and negative evidence.
SEC-005-S3 diagnosis
Explain why a reused recovery code must be rejected.
SEC-005-S4 decision
Defend a bounded verification-window and attempt policy using evidence.
SEC-005-S5 transfer
Adapt recovery controls when the primary factor changes to passkey.
Assessment rubric
Critical dimensions: bounded security model correctness, evidence quality, scope discipline, and transfer independence. A happy-path-only submission is insufficient.
References & freshness
Case studies
Lab files
Lesson media & slides
Teaching files (download)