Auth — Challenge MFA à la connexion¶
Module en Pre-Alpha
forge-mvc-mfa est marqué Development Status :: 2 - Pre-Alpha.
Le secret TOTP est actuellement stocké en clair dans la colonne
TotpSecret de la table auth_mfa_factors. Non recommandé en
production sensible sans protection additionnelle (restriction
d'accès à la table au minimum).
Le module n'est pas inclus dans forge-mvc[all] (cf. T3).
Installation depuis GitHub : voir installation-github.md.
Le chiffrement applicatif est planifié dans
SEC-MFA-SECRET-ENCRYPTION-001 — ticket post-1.0, tant que MFA reste Pre-Alpha.
À cette livraison, le module passera en Beta.
Module extrait : depuis Forge 2.5.0, le code MFA vit dans
forge-mvc-mfa. Voirpackages/forge-mvc-mfa/README.mdpour l'installation et l'API utilisateur. Cette page documente le flux de challenge MFA pour mémoire et référence rapide.
Le challenge MFA s'intercale entre la validation du mot de passe et l'ouverture de la session.
Flux général :
mot de passe correct + MFA désactivé → session ouverte (comportement inchangé)
mot de passe correct + MFA activé → état temporaire créé → /login/mfa
code MFA valide → état temporaire supprimé → session ouverte
code MFA invalide → état temporaire conservé → retour formulaire
État temporaire de challenge¶
| Clé de session | Rôle |
|---|---|
_auth_mfa_user_id |
Identifiant de l'utilisateur en attente de MFA |
_auth_mfa_started_at |
Timestamp ISO de début (expiration 10 min par défaut) |
L'état temporaire n'est pas une session authentifiée. L'utilisateur n'a aucun accès aux routes protégées tant que le code MFA n'est pas validé.
API forge_mvc_mfa¶
| Fonction | Comportement |
|---|---|
start_mfa_challenge(request, user) |
Stocke user.id et timestamp en session. Ne connecte pas l'utilisateur. Lève InvalidAuthUserError si utilisateur inactif. |
has_pending_mfa_challenge(request, max_age_minutes=10) |
Retourne True si challenge en cours et non expiré. |
get_mfa_challenge_user_id(request) |
Retourne l'identifiant en attente ou None. |
verify_mfa_challenge(request, code, factors, recovery_codes=None) |
Vérifie code TOTP ou de récupération. Retourne MfaChallengeResult ou None. Supprime le challenge en cas de succès. |
clear_mfa_challenge(request) |
Supprime les clés de challenge. Idempotent. |
Exemple d'intégration MVC¶
# Dans le contrôleur de login, après vérification du mot de passe :
from forge_mvc_mfa import is_mfa_enabled, start_mfa_challenge
from core.auth.user import AuthUser
mfa_factors = get_active_mfa_factors(user_id)
if is_mfa_enabled(mfa_factors):
auth_user = AuthUser(id=user_id, email=email, password_hash=hash, is_active=True)
start_mfa_challenge(request, auth_user)
return redirect("/login/mfa")
# Sinon : ouvrir la session directement
Limites actuelles (AUTH-MFA-004)¶
Forge ne fournit pas encore dans ce flux : remember device, WebAuthn, SMS, email MFA, gestion des codes de récupération dans le formulaire de connexion.
Politique de stockage des secrets MFA¶
Statut actuel¶
forge-mvc-mfa est Pre-Alpha. Le stockage des secrets MFA n'est pas production-ready en l'état.
Le module est opt-in, non inclus dans forge-mvc[all], et ne doit pas être présenté comme sécurisé en production sans protection additionnelle explicite.
Développement et tests¶
En développement et en environnement de test isolé, le stockage actuel est acceptable :
- le secret TOTP est stocké en clair dans
auth_mfa_factors.totp_secret; - les codes de récupération sont stockés sous forme hashée (
hash_recovery_code()— SHA-256 +secrets.compare_digest) ; - un avertissement
UserWarningest émis à la création d'un facteur TOTP (_warn_plaintext_secret_storage()).
Conditions requises même en développement :
- accès à la table
auth_mfa_factorslimité à l'utilisateur applicatif ; - secrets jamais loggés (
totp_secretetrecovery_codesont dans les champs redactés desanitize_auth_audit_metadata()) ; - base de données non exposée publiquement.
Production¶
Le stockage actuel n'est pas recommandé en production sensible sans protection additionnelle.
Raisons :
- le secret TOTP est stocké en clair — toute lecture directe de la base expose les secrets de tous les utilisateurs ;
- un secret TOTP exposé permet à un attaquant de générer des codes TOTP valides indéfiniment ;
- la révocation d'un secret exposé nécessite de désactiver et recréer tous les facteurs TOTP concernés.
Protections minimales si le déploiement en production ne peut pas attendre SEC-MFA-SECRET-ENCRYPTION-001 :
- restreindre les droits d'accès à la table
auth_mfa_factorsau strict minimum applicatif ; - chiffrement du disque de la base de données ;
- surveillance des accès directs à la table ;
- ne pas exporter
auth_mfa_factorsdans des dumps non chiffrés.
Ces mesures réduisent le risque sans l'éliminer. Elles ne remplacent pas le chiffrement applicatif.
Secrets TOTP¶
Le secret TOTP est une clé partagée utilisée pour calculer les codes TOTP (RFC 6238).
Pourquoi on ne peut pas simplement hasher le secret TOTP :
Un hash est à sens unique. Pour vérifier un code TOTP, le serveur doit pouvoir recalculer TOTP(secret, timestamp). Si le secret est hashé, cette opération est impossible.
Le stockage production-ready d'un secret TOTP nécessite :
- un chiffrement applicatif réversible (AES-256-GCM ou équivalent avec clé de chiffrement séparée), ou
- un HSM (Hardware Security Module), ou
- un gestionnaire de secrets (Vault, AWS Secrets Manager, ou équivalent).
Aucune de ces protections n'est implémentée dans forge-mvc-mfa 3.0.x. C'est l'objet du ticket SEC-MFA-SECRET-ENCRYPTION-001.
Codes de récupération¶
Les codes de récupération sont correctement protégés dans forge-mvc-mfa 3.0.x :
- générés via
secrets.choice()sur un alphabet sans ambiguïté ; - hashés avant stockage via
hash_recovery_code()(SHA-256) ; - vérifiés via
secrets.compare_digest()(résistant aux timing attacks) ; - stockés en base uniquement sous forme de hash — le code brut n'est jamais persisté.
Cette conception est conforme pour la production, à condition que la base elle-même soit protégée. Un hash de code de récupération exposé ne permet pas de retrouver le code brut.
Exigences avant production-ready¶
forge-mvc-mfa ne sera pas déclaré Beta tant que les exigences suivantes ne sont pas satisfaites :
- Chiffrement applicatif des secrets TOTP (
SEC-MFA-SECRET-ENCRYPTION-001) — clé de chiffrement séparée des données. - Politique de rotation documentée — rotation ou invalidation maîtrisée des secrets compromis.
- Documentation de sauvegarde/restauration — procédure en cas de perte de la clé de chiffrement.
- Tests dédiés au stockage chiffré — couverture de la création, vérification et rotation.
- Revue sécurité explicite — validation que le stockage chiffré est correct.
- Décision explicite de changement de statut — ticket de passage Pre-Alpha → Beta.
Tickets liés¶
| Ticket | Description | État |
|---|---|---|
MFA-SECRET-STORAGE-POLICY-001 |
Documenter la politique de stockage | livré |
SEC-MFA-SECRET-ENCRYPTION-001 |
Chiffrement applicatif du secret TOTP | post-1.0 |
OPTIN-PYPI-PUBLISH-001 |
Publication PyPI de forge-mvc-mfa | conditionné à SEC-MFA-SECRET-ENCRYPTION-001 |