kanidm/designs/mfa_backup_code.rst

64 lines
3.2 KiB
ReStructuredText
Raw Permalink Normal View History

Account recovery (backup) mfa codes draft design
------------------------
MFA requires users to have access to a working physical device, however that might not be always possible.
Backup mfa code allows:
- single-device accounts to be restored
- initial setup for passwordless-login
Overview
------------------------
If the user has a Backup code, then they can replace the TOTP/WebAuthn challenge with it during login. For example, TOTP + password auth will be Backup code + password instead.
To implement this, we can add Backup code as a new AuthCredential, so that it can be used in the auth process.
To validate Backup code, we simply check if the input matches the Backup code saved in database, which should be hashed with salt (similar to how password is validated).
The login session should only last for 5 mins with a Claim that allows users to change login credentials.
Code Generation
------------------------
The Backup code could be generated by a cryptographically secure pseudorandom number generator. Attackers should not be able to guess it even if they know our source code.
(See kanidmd/src/lib/utils.rs readable_password_from_random)
Implementation
------------------------
Add a new class/object: Backup code
A user can generate one batch of Backup codes at a time, which will be saved in the database in a non-reversible format (KDF)
- Each code in the batch can be used only once
- If the user generates a new batch of Backup codes, the last batch of codes become invalid.
To invalidate the Backup code after usage, we should send an async message to the async task queue. Since the auth process is currently in a single transaction lock that is NOT writeable, using an async action allows the auth process to proceed in parallel and prevent opening nested transactions. **Note** that there is a small window between "use of the backup code" and the async action being processed to actually cause the invalidation, but this window is short enough that it's an acceptable compromise.
To prevent attackers from bruteforcing these Backup code at a high rate, we need a rate limiting mechanism similar to what exists for passwords:
* After 5 incorrect attempts the account is rate limited by an increasing time window within the API. This limit delays the response to the auth (regardless of success)
* After X attempts, the account is soft locked on the affected server only for a time window of Y increasing up to Z.
* If the attempts continue, the account is hard locked and signalled to an external system that this has occured.
(See designs/account_policy.rst#rate-limiting for details)
Access Control
================
With the existing access profile infrastructure, we can decide which users/groups can self-admin the Backup code via a membership to a ``idm_account_mfa_backup_code_self_priv`` group.
If users want to admin Backup codes for others, they have to be members of the ``idm_account_mfa_backup_code_manage_priv`` group.
(See kanidmd/src/lib/constants/entries.rs for examples of existing groups for privileges)
Workflow
================
1. User can generate Backup code themselves if they are already authenticated (for later use)
2. User login with the Backup code when they have no access to TOTP/WebAuth token