امنیت، هویت، استقرار و تابآوری · فصل ۱ — Threat Model، Access و Session · 82
TOTP و Recovery Codes
دانش فعلی دربارهی «TOTP و Recovery Codes» ممکن است checklist-محور باشد و threat/control boundary را به evidence قابل بازبینی تبدیل نکند. میتواند برای «TOTP و Recovery Codes» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
خلاصهٔ درس
دانش فعلی دربارهی «TOTP و Recovery Codes» ممکن است checklist-محور باشد و threat/control boundary را به evidence قابل بازبینی تبدیل نکند.
میتواند برای «TOTP و Recovery Codes» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
خروجی این درس
میتواند برای «TOTP و Recovery Codes» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
نتیجه محدود درس
در پایان این درس باید بتوانید در یک fixture کاملاً محلی و مصنوعی، رفتار TOTP را با دادههای استاندارد بررسی کنید، policy مربوط به time-step، verification window و attempt limit را صریح کنید، و چرخه عمر Recovery Code را طوری ثبت کنید که استفادهٔ موفق، جلوگیری از reuse، و regeneration/revocation قابل مشاهده باشد. خروجی اصلی شما MFA Recovery Control Record v1 است.
این درس اثبات امنیت یک محصول واقعی نیست. هیچ حساب واقعی، seed واقعی، کد بازیابی واقعی یا target خارجی در آزمایشگاه وجود ندارد.
چرا این موضوع خطاپذیر است؟
TOTP در ظاهر فقط یک عدد کوتاه است، اما مدل امنیتی آن به یک secret مشترک بلندمدت، ساعت/گام زمانی سازگار، window پذیرش محدود و کنترل تلاش وابسته است. Recovery Code نیز «راه فرعی بیاهمیت» نیست؛ یک مسیر جایگزین برای بازپسگیری authority حساب است و اگر reusable، ضعیف ذخیرهشده یا بدون چرخهٔ revoke/regenerate باشد میتواند مرز MFA را بیاثر کند.
مدل ذهنی
مسیر عادی را به چهار جزء جدا کنید:
- TOTP seed: secret بلندمدت مشترک بین authenticator و verifier. این secret با OTP کوتاه نمایشدادهشده یک چیز نیست.
- Time moving factor: زمان Unix به counter تبدیل میشود؛ prover و verifier باید روی time-step و algorithm سازگار باشند.
- Verification policy: فقط تولید کد کافی نیست؛ window، TTL عملی، attempt limit و رفتار replay باید policy مشخص داشته باشند.
- Recovery path: recovery code یک authentication secret جایگزین است؛ مصرف موفق باید آن را از چرخه خارج کند و regeneration باید set قبلی را revoke کند.
پایهٔ استاندارد TOTP
RFC 6238 مدل TOTP را بهعنوان HOTP با moving factor زمانی تعریف میکند. fixture این درس از test vectorهای RFC استفاده میکند تا learner بتواند implementation محلی را بدون service خارجی verify کند. test vector فقط صحت الگوریتم در boundary مشخص را نشان میدهد؛ policy محصول واقعی از آن نتیجه نمیشود.
Time-step و verification window
در fixture، time-step پایه ۳۰ ثانیه است. verification window تعداد stepهای مجاور قابل قبول را مشخص میکند. بزرگتر کردن window ممکن است تحمل clock drift را افزایش دهد، اما همزمان سطح پذیرش کد را گستردهتر میکند. بنابراین window باید یک تصمیم صریح و قابل ثبت باشد، نه یک عدد نامحدود برای «حل مشکل login».
Attempt limit
کد کوتاه فضای محدودی دارد؛ verification endpoint نباید تلاش نامحدود بپذیرد. آزمایشگاه max_attempts=3 را بهعنوان policy مصنوعی استفاده میکند و پس از عبور از حد، تلاشهای بیشتر را تا reset محلی رد میکند. این عدد یک توصیه جهانی برای همه سامانهها نیست؛ هدف تمرین این است که attempt policy قابل مشاهده و auditable باشد.
Secret boundary
TOTP seed material باید از OTP خروجی جدا دیده شود. fixture از secret عمومی RFC فقط برای test vector استفاده میکند؛ این secret credential واقعی نیست. در evidence record نباید raw secret واقعی ثبت شود. همچنین hash کردن یک OTP ششرقمی، مقاومت offline مشابه password hashing ایجاد نمیکند؛ فضای جستوجوی آن کوچک است. هدف اصلی کنترل lifecycle و exposure است.
Recovery Codes
Recovery Code یک backup authentication secret است. در مدل این درس:
- codeها فقط در زمان issue بهصورت plaintext مصنوعی به learner برگردانده میشوند؛ state ذخیرهشده فقط digest دارد.
- هر code فقط یکبار قابل مصرف است.
- reuse همان code باید رد شود.
- regeneration یک set جدید میسازد و set قبلی را revoke میکند.
- رویدادهای use و regeneration در evidence log ثبت میشوند.
مسیر مثبت و شواهد منفی
Happy path کافی نیست. حداقل شواهد لازم:
- RFC vector درست باید PASS شود.
- TOTP خارج از window باید رد شود.
- عبور از attempt limit باید قابل مشاهده باشد.
- recovery code معتبر یک بار موفق شود.
- همان recovery code در reuse رد شود.
- پس از regeneration، تمام codeهای set قبلی رد شوند.
- evidence record باید residual risk را جدا از observation ثبت کند.
Negative Evidence
شواهد منفی در این درس حذف نمیشوند. اگر window را عمداً بزرگ کردید یا یک recovery code مصرفشده را دوباره امتحان کردید، خروجی ردشدن باید کنار مسیر مثبت باقی بماند. تصمیم نهایی باید به هر دو نوع evidence تکیه کند.
جدول MFA Recovery Control Record v1
برای هر ردیف این فیلدها را کامل کنید:
| فیلد | منظور |
|---|---|
| Factor/Recovery Item | TOTP یا recovery code/set |
| Secret Material | نوع secret، نه secret واقعی |
| Lifetime or Window | time-step/window یا lifecycle code |
| Attempt Policy | حد و رفتار تلاش ناموفق |
| Storage Boundary | محل/شکل نگهداری در fixture |
| Successful Use Effect | اثر authentication/recovery موفق |
| Reuse Expected | آیا reuse باید رد شود؟ |
| Regeneration Effect | اثر ساخت set جدید |
| Evidence | observation قابل بازتولید |
| Residual Recovery Risk | ریسک باقیمانده/مرز تصمیم |
Worked Example 1 — RFC vector
fixture مقدار RFC برای timestamp 59 را با SHA-1 و ۸ رقم بررسی میکند و 94287082 باید حاصل شود. این test فقط algorithm parity را verify میکند.
Worked Example 2 — window mutation
policy پایه window یک step مجاور است. learner window را در mutation کنترلشده بزرگ میکند و در record توضیح میدهد که پذیرش زمانهای بیشتری ایجاد شده است. «کار کردن login» بهتنهایی justification نیست.
Worked Example 3 — Recovery reuse
یک code مصنوعی مصرف میشود و PASS میگیرد. اجرای همان code دوباره باید RECOVERY_CODE_REUSED_OR_INVALID برگرداند. اگر reuse موفق شود، lifecycle invariant شکسته است.
Worked Example 4 — regeneration
قبل از regeneration یک code قدیمی نگه دارید. set جدید را بسازید. code قدیمی باید پس از regeneration رد شود و event log باید RECOVERY_SET_REGENERATED را نشان دهد.
Failure modes
- ذخیره یا log کردن seed واقعی در evidence.
- window نامحدود یا تغییر window بدون ثبت trade-off.
- عدم وجود attempt limit.
- reusable recovery code.
- regeneration بدون revoke کردن set قبلی.
- برابر فرض کردن TOTP و passkey از نظر phishing resistance.
- تبدیل guidance سازمانی/فدرال به الزام جهانی بدون context.
Workflow شواهد: از prediction تا decision
قبل از اجرای هر probe، نتیجه مورد انتظار را بنویسید. سپس observation واقعی را جدا ثبت کنید و در ستون Evidence به event/status مشخص ارجاع دهید. بعد از observation، inference را بنویسید. این جداسازی مهم است: «کد پذیرفته شد» observation است، اما «policy ما برای این threat کافی است» یک inference و تصمیم انسانی است.
یک workflow قابل بازتولید برای این درس چنین است:
- policy پایه را از
golden-policy.jsonبخوانید و بدون تغییر اجرا کنید. - test vectorهای RFC را بررسی کنید تا implementation algorithmic mismatch نداشته باشد.
- یک کد معتبر را در window پایه verify کنید و counter پذیرفتهشده را ثبت کنید.
- همان counter را دوباره استفاده کنید و rejection replay را نگه دارید.
- چند تلاش نامعتبر انجام دهید تا attempt-boundary قابل مشاهده شود.
- یک recovery code را مصرف کنید و سپس reuse همان code را امتحان کنید.
- recovery set را regenerate کنید و یک code استفادهنشده از set قدیمی را دوباره امتحان کنید.
- در پایان، residual risk را بنویسید؛ از جمله اینکه recovery هنوز یک alternate authority path است و مدل local این درس identity proofing واقعی را پوشش نمیدهد.
تفاوت algorithm correctness با security policy
در این درس دو نوع سؤال عمداً جدا هستند. سؤال اول این است که «آیا implementation TOTP با vector شناختهشده سازگار است؟» این را میتوان با RFC vector جواب داد. سؤال دوم این است که «چه window، attempt policy و recovery lifecycle برای یک سامانه مشخص مناسب است؟» پاسخ دوم به context، threat model، usability و الزامات سامانه وابسته است. عبور از vector اول، پاسخ دوم را اثبات نمیکند.
همین تفکیک برای recovery code نیز برقرار است. اینکه digest lookup و single-use logic در fixture کار میکند، فقط یک invariant محلی را نشان میدهد. این نتیجه بهتنهایی نمیگوید فرایند واقعی صدور یا identity verification سازمان شما امن است.
Storage boundary و log discipline
Evidence باید برای تصمیم کافی باشد ولی نباید secret واقعی را جمعآوری کند. برای TOTP میتوان شناسه fixture، algorithm، digits، time-step، window، counter نتیجه و status را ثبت کرد؛ raw seed واقعی لازم نیست. برای recovery code نیز میتوان generation، نتیجه consume و event را ثبت کرد، بدون ذخیره plaintext code در report. در fixture آموزشی، codeها synthetic هستند تا learner بتواند lifecycle را ببیند، اما همان الگو نباید به logging production secret تبدیل شود.
Replay و مفهوم one-time
یک TOTP از نظر الگوریتم در یک time-step ممکن است همان مقدار را برای چند request تولید کند. اگر verifier هیچ state مصرفی نگه ندارد، یک code میتواند در همان window دوباره پذیرفته شود. fixture این درس replay protection را با used_counters مدل میکند تا learner تفاوت «time-based» و «one-time enforcement» را ببیند. این یک design آموزشی bounded است؛ معماری production میتواند state و concurrency متفاوتی داشته باشد، اما باید رفتار replay مورد انتظار را صریح تعریف کند.
Concurrency و race boundary
در یک سامانه واقعی، دو request همزمان میتوانند برای یک OTP یا recovery code برسند. fixture single-process این درس race production را شبیهسازی نمیکند. بنابراین record باید این محدودیت را در residual risk نگه دارد. invariant مورد انتظار همچنان روشن است: یک recovery code نباید دو authority grant مستقل ایجاد کند، و اگر implementation واقعی concurrent است باید مصرف code بهصورت اتمیک enforce شود.
Experienced bridge
برای learner باتجربه، هدف نوشتن TOTP از صفر نیست. میتوانید implementation الگوریتم را به یک library معتبر بسپارید، اما evidence requirements حذف نمیشوند: policy window، attempt behavior، secret boundary، replay expectation، recovery single-use و regeneration/revocation باید inspectable باشند. abstractions سطح بالا نباید contract امنیتی را پنهان کنند.
Alternatives و trade-offs
Passkey/WebAuthn میتواند phishing resistance متفاوتی نسبت به TOTP فراهم کند، اما تغییر primary factor باعث حذف خودکار recovery governance نمیشود. SMS یا email OTP نیز فقط به این دلیل که «OTP» هستند معادل TOTP نیستند و dependencyهای threat متفاوت دارند. این درس مقایسه محصولی جامع انجام نمیدهد؛ فقط learner را مجبور میکند factor اصلی و recovery path را جدا model کند و ادعای equivalence نسازد.
Evidence completeness gate
یک record وقتی برای این درس کامل است که حداقل یک positive path، یک negative path، یک attempt/replay boundary، یک recovery reuse rejection، یک regeneration/revocation observation و یک transfer decision داشته باشد. اگر یکی از اینها حذف شود، outcome درس نباید صرفاً بهخاطر سبز بودن happy path «کامل» اعلام شود.
Transfer
سناریوی انتقال: یک operator مصنوعی از TOTP-primary به passkey-primary میرود اما recovery codes اضطراری را نگه میدارد. شما باید تعیین کنید کدام controls recovery همچنان لازماند، بدون اینکه TOTP و passkey را از نظر assurance برابر اعلام کنید. تصمیم باید بر evidence lifecycle recovery استوار باشد.
Non-goals
- TOTP را phishing-resistant همسطح WebAuthn نمیدانیم.
- hash یک OTP کوتاه را جایگزین حفاظت seed نمیدانیم.
- recovery code reusable را مجاز نمیدانیم.
- recovery را مجاز به ضعیفتر کردن authentication اصلی بدون risk justification نمیدانیم.
ارزیابی
پاسخ نهایی باید retrieval، application، diagnosis، decision و transfer را پوشش دهد. مسیر blocking شامل اجرای fixture، ثبت negative evidence و transfer مستقل است. AI میتواند probe دفاعی پیشنهاد دهد یا observationها را مرتب کند، اما حق اختراع evidence یا تصمیم نهایی residual risk را ندارد.
منابع و freshness
Source boundary این درس دقیقاً سه منبع frozen است: RFC6238، OWASP-MFA و NIST-800-63-4. در 2026-09-16 یک بررسی current داخل همین boundary انجام شد؛ review_due بعدی 2026-10-02 است. هیچ source جدیدی authority نشده است.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
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.
ملاکهای ارزیابی (rubric)
Critical dimensions: bounded security model correctness, evidence quality, scope discipline, and transfer independence. A happy-path-only submission is insufficient.
منابع و تازگی
مطالعهٔ موارد (case studies)
فایلهای آزمایشگاه
رسانه و اسلایدهای درس
فایلهای آموزشی (دانلود)