Un serveur ne doit jamais conserver les mots de passe de ses…
Exercice supplémentaire · niveau 3 (difficile) · NSI (première), chapitre 10 — Interagir sur le Web · Le serveur, de plus près
Énoncé
Un serveur ne doit jamais conserver les mots de passe de ses utilisateurs.
- Que garde-t-il alors, et comment vérifie-t-il une connexion ?
- Deux comptes ont choisi le même mot de passe. Sans précaution, cela se voit dans la base. Pourquoi, et comment l'empêcher ?
- Écrire le code Python correspondant et le vérifier.
Corrigé
1. Il garde une empreinte — le résultat d'une fonction de hachage appliquée au mot de passe. Cette fonction se calcule facilement dans un sens et pratiquement pas dans l'autre. À la connexion, le serveur recalcule l'empreinte de ce qu'on lui envoie et la compare à celle qu'il a rangée. Il vérifie donc l'égalité sans jamais avoir su le mot de passe — et le jour où sa base est volée, les mots de passe ne sont pas dedans.
2. Une fonction de hachage est déterministe : le même mot de passe donne toujours la même empreinte. Deux lignes identiques dans la base trahiraient donc deux comptes ayant choisi le même mot de passe — et l'un des deux suffirait à ouvrir l'autre. Pire : un attaquant peut précalculer les empreintes des mots de passe courants et les chercher dans la base.
La parade est le sel : une valeur aléatoire, tirée à l'inscription, différente pour chaque compte, rangée en clair à côté de l'empreinte et mélangée au mot de passe avant hachage. Deux comptes de même mot de passe ont alors deux empreintes différentes, et aucune table précalculée ne sert plus à rien.
3.
import hashlib
def empreinte(motdepasse, sel):
"""Empreinte salee d'un mot de passe. Le sel est une suite d'octets."""
return hashlib.sha256(sel + motdepasse.encode("utf-8")).hexdigest()
sel_nour = bytes.fromhex("9f1c4a") # tire au hasard a l'inscription
sel_yanis = bytes.fromhex("4b7e02")
a = empreinte("azerty", sel_nour)
b = empreinte("azerty", sel_yanis)
print(a[:16], b[:16])
print("empreintes differentes :", a != b)
print("verification de Nour :", empreinte("azerty", sel_nour) == a)
print("mauvais mot de passe :", empreinte("qwerty", sel_nour) == a)
Contrôle : le même mot de passe donne deux empreintes différentes selon le sel, et la vérification reste possible parce que le sel est rangé avec l'empreinte. Le programme affiche True pour la vérification et False pour le mauvais mot de passe.
Ce que ce corrigé simplifie. En production, SHA-256 ne convient pas : il est trop rapide. Une carte graphique en calcule des milliards par seconde, donc essaie des milliards de mots de passe par seconde. On emploie une fonction délibérément lente et réglable — bcrypt, scrypt, argon2 — qu'on ajuste pour qu'une vérification coûte une fraction de seconde. Tout cela est très au-delà du programme ; le principe du sel, lui, se comprend au niveau de la première.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.