Politique de mot de passe
Des règles de mot de passe par tenant et par groupe alignées sur NIST 800-63B et l'ANSSI, la longueur d'abord, des contrôles de fuite entièrement locaux, et des options de conformité quand un référentiel les impose.
Obexal suit les recommandations modernes de NIST 800-63B et de l'ANSSI : la longueur et les listes de blocage protègent les comptes, la complexité imposée et l'expiration périodique non. Les défauts en découlent, et tout ce que ces référentiels déconseillent est désactivé par défaut mais disponible pour les référentiels de conformité qui l'imposent. La politique s'applique partout où un mot de passe est défini : inscription, activation d'invitation, changement et réinitialisation.
Des défauts alignés NIST et ANSSI
| Réglage | Défaut | Bornes |
|---|---|---|
minLength | 12 | 8 à 128 |
rejectBreached | true | |
rejectContextual | true | |
requireLower, requireUpper, requireDigit, requireSymbol | false | |
historyCount | 0 (désactivé) | 0 à 24 |
maxAgeDays | 0 (n'expire jamais) | 0 à 3650 |
La longueur minimale par défaut de 12 suit l'ANSSI 2024 (12 à 16 pour les comptes utilisateurs) et NIST 800-63B Rev. 4. Un tenant peut l'abaisser, mais 8 est un plancher dur appliqué côté serveur quoi que dise la configuration. Les mots de passe jusqu'à 256 caractères sont acceptés : les phrases de passe fonctionnent.
Mots de passe compromis, vérifiés en local
Avec rejectBreached actif, chaque mot de passe candidat est vérifié contre deux sources : une liste embarquée de mots de passe triviaux, et un corpus optionnel plus large au format HIBP (lignes SHA1:count, ou texte brut à raison d'un mot de passe par ligne) chargé au démarrage depuis un fichier local (BREACHED_PASSWORD_FILE). La comparaison se fait par hash SHA-1, entièrement en mémoire.
Aucun appel externe n'est émis : pas de requête vers l'API HaveIBeenPwned ni vers aucun tiers, le mot de passe (ou un dérivé) ne quitte jamais la plateforme. Voir Résidence des données et souveraineté. En auto-hébergement, montez le corpus vous-même, voir Configuration.
Mots de passe contextuels et garde d'entropie
Avec rejectContextual actif, un mot de passe contenant l'e-mail de l'utilisateur (sa partie locale) ou son nom est refusé, sans tenir compte de la casse, pour les fragments de 4 caractères et plus. alice.martin2026! n'est pas un mot de passe quand votre identifiant est alice.martin@example.com.
Indépendamment de tout réglage, une garde d'entropie est toujours active. Volontairement conservatrice, elle ne rejette que deux motifs flagrants qui passent pourtant le seuil de longueur : moins de 4 caractères distincts (aaaaaaaaaaaa, abababababab) et les suites strictement croissantes ou décroissantes (abcdefghijkl). Une vraie phrase de passe ne la déclenche jamais.
Options de conformité
Les exigences de classes de caractères (requireLower, requireUpper, requireDigit, requireSymbol), l'historique anti-réutilisation (historyCount) et l'expiration périodique (maxAgeDays) sont exposés pour les référentiels qui les imposent, et désactivés par défaut parce que NIST et ANSSI les déconseillent.
- L'historique refuse un nouveau mot de passe identique à l'un des N derniers (vérifié contre les hashs stockés, N jusqu'à 24). En cas d'incident de stockage, le contrôle est sauté plutôt que de bloquer un changement légitime.
- Avec l'expiration active, un mot de passe correct mais trop ancien est refusé à la connexion (aucune session ouverte, raison d'audit générique
password_expired) ; l'utilisateur le renouvelle via la réinitialisation de mot de passe.
Dérogations par groupe, la plus stricte l'emporte
Au-dessus de la politique du tenant, un groupe peut porter une dérogation : la politique effective d'un utilisateur est la fusion champ par champ de la politique du tenant et des dérogations de tous ses groupes, en gardant toujours la valeur la plus exigeante. Longueurs et historique prennent le maximum, les exigences booléennes se combinent par OU logique, l'expiration prend le plus petit âge non nul. Une dérogation ne peut donc que durcir, jamais affaiblir. Les utilisateurs se gèrent dans les groupes.
| Méthode et chemin | Effet |
|---|---|
GET /v1/admin/password-policy/groups | Lister les dérogations par groupe |
PUT /v1/admin/password-policy/groups/{groupId} | Poser la dérogation d'un groupe |
DELETE /v1/admin/password-policy/groups/{groupId} | La retirer (retour à la politique du tenant) |
Stockage, Argon2id
Les mots de passe sont hachés avec Argon2id et stockés au format PHC ($argon2id$v=19$m=...,t=...,p=...$sel$hash). Ils ne sont jamais stockés ni journalisés en clair, et les erreurs de validation renvoient un message générique qui ne renvoie pas le candidat.
Gérer la politique par l'API
Les deux endpoints exigent la permission tenant:manage, avec un jeton d'API admin (Authorization: Bearer obx_...). Un domaine personnalisé remplace accounts.obexal.com. Chaque changement est consigné au journal d'audit.
curl -sS https://accounts.obexal.com/v1/admin/password-policy \
-H "Authorization: Bearer $OBEXAL_API_TOKEN"{
"policy": {
"minLength": 12,
"rejectBreached": true,
"rejectContextual": true,
"requireLower": false, "requireUpper": false,
"requireDigit": false, "requireSymbol": false,
"historyCount": 0,
"maxAgeDays": 0
}
}curl -sS -X PUT https://accounts.obexal.com/v1/admin/password-policy \
-H "Authorization: Bearer $OBEXAL_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"minLength": 14, "rejectBreached": true, "rejectContextual": true,
"requireLower": false, "requireUpper": false, "requireDigit": false,
"requireSymbol": false, "historyCount": 5, "maxAgeDays": 0}'
# 204 No ContentLe PUT remplace la politique entière : envoyez tous les champs, pas seulement celui que vous changez.