Files
pta/docs/README_V7_12.md
2026-08-20 17:00:06 +02:00

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 :

  1. la DSI crée le compte et remet le jeton ;
  2. à la première connexion, le jeton est reconnu et l'écran impose de choisir un mot de passe ;
  3. 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.