7.1 KiB
PTA V7.12 — Second facteur pour les comptes Service Enfance et DSI
Le problème traité
La V7.11 a remplacé le sélecteur de rôle par un jeton personnel. C'était un progrès décisif, mais un jeton reste un secret qui circule : il est produit par la DSI, transmis par courriel ou sur papier, parfois recopié dans un carnet. Un jeton intercepté suffisait à valider les plannings de toute la collectivité (Service Enfance), voire à distribuer de nouveaux accès (DSI).
Le risque n'est pas le même selon le compte. Un agent ne peut que lire son propre planning ; un responsable ne touche qu'aux brouillons de son lieu. Ces deux rôles-là restent à un seul facteur — alourdir leur connexion coûterait plus qu'il ne protégerait.
Ce qui change
1. Deux facteurs, mais seulement là où c'est justifié
| Rôle | Jeton | Mot de passe |
|---|---|---|
| Agent | oui | — |
| Responsable de structure | oui | — |
| Service Enfance | oui | oui |
| DSI | oui | oui |
La règle vit en base, dans la vue v_acces_compte (mot_de_passe_requis), comme le reste des
droits depuis la V7.8 : étendre le second facteur à un autre rôle est une modification SQL, pas un
redéploiement.
Les deux secrets sont volontairement de nature différente : le jeton est remis par la DSI, le mot de passe est choisi par le titulaire et n'est jamais affiché nulle part.
2. Le mot de passe se choisit à la première connexion
La DSI ne pose aucun mot de passe initial, et ne peut donc en connaître aucun. Le parcours :
- la DSI crée le compte et remet le jeton ;
- à la première connexion, le jeton est reconnu et l'écran impose de choisir un mot de passe ;
- aux connexions suivantes : jeton, puis mot de passe.
Entre les deux étapes, rien n'est ouvert : la session ne porte qu'une attente horodatée, périmée
au bout de cinq minutes. Un jeton validé sans mot de passe ne donne accès à aucune page — vérifié :
dsi.php renvoie alors vers l'écran de connexion.
Le compte est relu en base entre les deux étapes : si la DSI révoque le compte pendant que l'utilisateur tape son mot de passe, la session ne s'ouvre pas.
3. Politique : la longueur, et rien d'autre
- 12 caractères minimum, 72 maximum. Aucune règle de composition : exiger une majuscule et un
chiffre produit
Motdepasse1, pas un secret. Une phrase dont on se souvient vaut mieux. - La borne haute n'est pas arbitraire :
password_hash()utilise bcrypt, qui ignore silencieusement tout ce qui dépasse 72 octets. Mieux vaut refuser que laisser croire. - Le jeton lui-même est refusé comme mot de passe : le recopier ramènerait les deux facteurs à un seul secret.
- Hachage par
password_hash()(bcrypt), avec remise à niveau automatique si PHP change d'algorithme par défaut. C'est un secret choisi par un humain, donc attaquable par dictionnaire : contrairement au jeton, le hachage lent a ici tout son sens.
4. Changement et oubli
- Changer son mot de passe : bouton « Mot de passe » dans l'en-tête, visible des seuls comptes concernés. L'ancien mot de passe est exigé — sans quoi un poste laissé ouvert suffirait à confisquer un compte.
- Oubli : la DSI efface le mot de passe depuis sa page (bouton « Effacer le mot de passe »). Elle ne le remplace pas : le titulaire en choisit un nouveau à sa connexion suivante, avec son jeton inchangé. La DSI ne connaît donc jamais le mot de passe de personne, pas même à l'instant de la réinitialisation.
- La colonne « État » de la liste des comptes affiche « Mot de passe défini » ou « Mot de passe à définir ». Le second n'est pas une anomalie : c'est l'état normal d'un compte neuf.
5. Le frein anti-force-brute couvre les deux facteurs
Le compteur du journal (JournalModel::echecsRecents()) additionne désormais JETON_REFUSE et
MOT_DE_PASSE_REFUSE : essayer mille mots de passe derrière un jeton volé bute sur le même mur
qu'essayer mille jetons — 10 échecs en 15 minutes par adresse IP, puis plus rien n'est comparé.
6. Ce que le journal enregistre en plus
| Action | Catégorie | Quand |
|---|---|---|
JETON_ACCEPTE_ATTENTE_MDP |
CONNEXION |
Jeton reconnu, mot de passe attendu |
MOT_DE_PASSE_REFUSE |
CONNEXION |
Mot de passe incorrect derrière un jeton valide |
MOT_DE_PASSE_DEFINI |
ECRITURE |
Premier choix par le titulaire |
MOT_DE_PASSE_MODIFIE |
ECRITURE |
Changement par le titulaire |
MOT_DE_PASSE_REINITIALISE |
ADMINISTRATION |
Effacement par la DSI |
CONNEXION_REUSSIE porte en contexte les facteurs réellement présentés (["jeton"] ou
["jeton","mot_de_passe"]) : le journal distingue donc une connexion à un facteur d'une connexion à
deux.
Mise en service
Rien à faire hors la migration database/migration_v7_9f_mot_de_passe_admin.sql, appliquée
automatiquement au démarrage. Les comptes Service Enfance et DSI existants n'ont pas de mot de
passe : leur prochaine connexion, jeton en main, leur en fera choisir un. Aucun jeton n'est
invalidé, aucun compte n'est bloqué.
Prévenez les titulaires concernés : ils verront un écran qu'ils n'attendent pas.
Si le dernier accès DSI perd son mot de passe
Le cas ne se résout pas dans l'interface, puisqu'il faudrait être connecté pour le faire. En SQL :
UPDATE compte_acces SET mot_de_passe_hash = NULL, date_mot_de_passe = NULL WHERE id_compte = 1;
La connexion suivante, avec le jeton, redemandera d'en définir un. Si le jeton lui-même est perdu,
voir la procédure de README_V7_11.md.
Fichiers
| Fichier | Rôle |
|---|---|
database/migration_v7_9f_mot_de_passe_admin.sql |
Colonnes mot_de_passe_hash / date_mot_de_passe, vue v_acces_compte enrichie de mot_de_passe_requis et mot_de_passe_defini |
app/Controllers/RoleController.php |
Connexion en deux étapes, définition, vérification, changement |
app/Models/CompteModel.php |
Politique, hachage, vérification, réinitialisation |
app/Models/JournalModel.php |
Frein étendu au second facteur |
app/Controllers/DsiController.php, api/dsi_compte_mot_de_passe.php |
Effacement par la DSI |
app/Views/pages/role.php |
Les quatre états de l'écran de connexion |
app/Views/layouts/header.php |
Lien « Mot de passe », pour les seuls comptes concernés |
Ce que la V7.12 ne fait pas
- Pas de verrouillage du compte après N échecs : seul le frein par adresse IP s'applique. Un verrouillage par compte permettrait à quiconque connaît un jeton de bloquer volontairement un administrateur.
- Pas d'expiration ni d'historique des mots de passe : forcer un changement tous les trois mois
produit
Motdepasse-Mars,Motdepasse-Juin. Le mot de passe se change quand il y a une raison. - Pas de réinitialisation par courriel : il n'y a pas d'envoi de courriel dans PTA, et la boîte aux lettres deviendrait le vrai facteur d'authentification.
- Pas de TOTP : le jeton joue déjà le rôle du « quelque chose que l'on détient ». Un authentificateur mobile serait le prolongement naturel si le besoin s'en faisait sentir.