Introduction
L'authentification multifacteur (MFA) réduit le risque de compromission des comptes en exigeant plus d'un type de preuve. Un mot de passe est quelque chose que l'utilisateur connaît. Un second facteur peut être un code provenant d'un appareil distinct, d'une application, d'un fichier ou d'un jeton matériel.
Dans ce laboratoire, vous partirez d'un script de connexion Python basé uniquement sur un mot de passe, puis vous ajouterez un second facteur simple. Pour que ce laboratoire reste accessible aux débutants et déterministe, le second facteur sera un code basé sur HMAC généré à partir d'un fichier secret protégé.
Tester la connexion par mot de passe seul
Dans cette étape, vous allez exécuter le script de connexion initial. Il vérifie uniquement un nom d'utilisateur et un mot de passe, ce qui constitue une authentification à facteur unique, car la seule preuve est quelque chose que l'utilisateur connaît.
Déplacez-vous dans le répertoire du projet :
cd /home/labex/project
Inspectez les fichiers préparés :
ls -l
Affichez la base de données des utilisateurs :
cat users.json
Effectuez une connexion réussie avec uniquement le mot de passe :
python3 login.py alice wonderland
Le résultat devrait être :
login ok
Essayez maintenant avec un mauvais mot de passe :
python3 login.py alice wrong
Cette commande devrait afficher login failed. Une connexion échouée se termine avec un statut différent de zéro, ce qui est normal pour ce test.
Exécutez le vérificateur pour l'état initial :
python3 mfa-check.py password-only
Le résultat attendu est :
password-only: complete
Créer le secret pour le second facteur
Dans cette étape, vous allez créer un secret distinct pour le second facteur. Dans un système MFA réel, ce secret pourrait résider dans une application d'authentification ou un jeton matériel. Dans ce laboratoire, il s'agit d'un fichier local afin que le comportement soit facile à inspecter et à vérifier.
Créez une valeur secrète :
printf 'labex-mfa-secret-2026\n' > mfa_secret.txt
Restreignez l'accès au fichier afin que seul le propriétaire puisse le lire et l'écrire :
chmod 600 mfa_secret.txt
Vérifiez les permissions :
ls -l mfa_secret.txt
Les bits de permission devraient commencer par -rw------- :
-rw------- ... mfa_secret.txt
Exécutez le vérificateur pour le secret :
python3 mfa-check.py secret
Le résultat attendu est :
secret: complete
Générer un code de connexion
Dans cette étape, vous allez créer un petit générateur de code. Il utilise HMAC-SHA256 pour combiner le fichier secret avec le nom d'utilisateur. HMAC est utile ici car la même entrée et le même secret produisent le même code court, mais quelqu'un ne possédant pas le secret ne peut pas facilement créer ce code.
Créez generate-code.py :
cat > generate-code.py <<'PY'
#!/usr/bin/env python3
import hmac
import hashlib
import sys
from pathlib import Path
if len(sys.argv) != 2:
print("usage: generate-code.py USERNAME")
raise SystemExit(2)
username = sys.argv[1]
secret = Path("mfa_secret.txt").read_text().strip().encode()
digest = hmac.new(secret, username.encode(), hashlib.sha256).hexdigest()
print(digest[:6])
PY
Rendez-le exécutable :
chmod +x generate-code.py
Générez un code pour alice :
python3 generate-code.py alice
Vous devriez voir ce code déterministe de six caractères :
21f18f
Exécutez le vérificateur pour le générateur :
python3 mfa-check.py generator
Le résultat attendu est :
generator: complete
Appliquer le second facteur
Dans cette étape, vous allez remplacer le script de connexion afin qu'il exige à la fois le mot de passe et le code généré. C'est le changement clé du MFA : le mot de passe seul ne suffit plus.
Remplacez login.py par cette version prenant en charge le MFA :
cat > login.py <<'PY'
#!/usr/bin/env python3
import hmac
import hashlib
import json
import sys
from pathlib import Path
USERS = Path("users.json")
SECRET = Path("mfa_secret.txt")
def expected_code(username):
secret = SECRET.read_text().strip().encode()
digest = hmac.new(secret, username.encode(), hashlib.sha256).hexdigest()
return digest[:6]
def main():
if len(sys.argv) != 4:
print("usage: login.py USERNAME PASSWORD MFA_CODE")
return 2
username, password, code = sys.argv[1], sys.argv[2], sys.argv[3]
users = json.loads(USERS.read_text())
if users.get(username, {}).get("password") != password:
print("login failed")
return 1
if not hmac.compare_digest(code, expected_code(username)):
print("mfa failed")
return 1
print("login ok")
return 0
if __name__ == "__main__":
raise SystemExit(main())
PY
Assurez-vous que le script est exécutable :
chmod +x login.py
Générez un nouveau code et enregistrez-le dans une variable shell :
CODE="$(python3 generate-code.py alice)"
Utilisez le bon mot de passe et le bon code ensemble :
python3 login.py alice wonderland "$CODE"
Le résultat devrait être :
login ok
Exécutez le vérificateur pour l'application du MFA :
python3 mfa-check.py enforced
Le résultat attendu est :
enforced: complete
Tester l'échec et la réussite du MFA
Dans cette étape, vous allez tester le comportement final de la connexion. Un mot de passe correct sans le second facteur devrait échouer, un code erroné devrait échouer, et le mot de passe correct combiné au code correct devrait réussir.
Tout d'abord, essayez l'ancienne commande avec uniquement le mot de passe :
python3 login.py alice wonderland || true
Le résultat devrait afficher le nouveau message d'utilisation car le code MFA est manquant :
usage: login.py USERNAME PASSWORD MFA_CODE
Essayez un code erroné :
python3 login.py alice wonderland 000000 || true
Le résultat devrait être :
mfa failed
Générez le code correct et connectez-vous :
CODE="$(python3 generate-code.py alice)"
python3 login.py alice wonderland "$CODE"
Le résultat devrait être :
login ok
Exécutez le vérificateur complet :
python3 mfa-check.py all
Le résultat final devrait montrer que tous les composants MFA sont terminés :
secret: complete
generator: complete
enforced: complete
Résumé
Vous avez transformé un script de connexion basé uniquement sur un mot de passe en un flux de connexion multifacteur simple. Vous avez créé un secret MFA distinct, généré un code basé sur HMAC, exigé ce code dans le script de connexion, et testé les cas d'échec et de réussite.
Le principe de sécurité fondamental est qu'un mot de passe volé ne doit pas suffire à lui seul lorsqu'une seconde preuve indépendante est requise.



