Laissez-moi juste saisir des chiffres
(gendignoux.com/blog)- La fenêtre de saisie du code de vérification par e-mail à 6 chiffres du système de connexion du gouvernement suisse AGOV ne gérait pas la saisie des chiffres sur les claviers AZERTY français, bloquant ainsi l’inscription au compte elle-même
- Le JavaScript du champ de saisie interceptait les frappes et stockait le code de vérification dans une variable séparée, tout en ignorant la touche Shift ; il bloquait donc de fait les dispositions AZERTY, qui nécessitent Shift pour saisir des chiffres
- La même erreur se produisait avec plusieurs combinaisons Firefox·Chromium·Chrome·Safari et Linux·macOS, mais le fonctionnement était normal avec un clavier QWERTY, ce qui a resserré le diagnostic sur un problème de disposition de clavier, et non de navigateur ou de système d’exploitation
- Le support officiel nécessitait lui aussi de passer la même vérification par e-mail, sans autre moyen comme l’e-mail ou le téléphone : les utilisateurs qui ne pouvaient pas se connecter ne pouvaient donc même pas signaler le bug de connexion
- Utiliser une logique complexe de gestion des touches au lieu de champs de saisie natifs, et lier le produit comme les canaux de support à la même procédure d’authentification, fait s’effondrer à la fois l’accessibilité et la gestion des incidents ; il faut donc une saisie simple basée sur le DOM et des canaux de support indépendants
AGOV comme infrastructure d’identité numérique
- L’identité numérique est récemment devenue un grand sujet de débat sur le Web, avec de nombreuses interdépendances et controverses
- L’impact des lois de vérification de l’âge sur l’anonymat en ligne
- La possibilité qu’au Royaume-Uni, Wikipedia doive vérifier l’identité de ses utilisateurs
- Le problème de la dépendance à iOS et Android officiels comme plateformes obligatoires pour les portefeuilles d’identité numérique
- Le cas de comptes numériques américains désactivés au motif que leurs titulaires étaient juges à la Cour pénale internationale
- Le système de connexion du gouvernement suisse AGOV est en service depuis 2024 et a atteint 1,6 million de comptes
- Il est étendu comme moyen de connexion pour plusieurs démarches administratives, notamment l’assurance chômage et les déclarations fiscales obligatoires
- Dans le canton de Zurich, c’est l’unique moyen de connexion pour accéder aux demandes de naturalisation
Une inscription bloquée à l’étape de vérification par e-mail
- La procédure d’inscription AGOV commence par la saisie d’une adresse e-mail, puis d’un code de vérification à 6 chiffres
- L’interface du code de vérification se compose de 6 champs de saisie, un par chiffre
- Quand on saisit un chiffre, le focus ne passe pas au champ suivant
- Les chiffres continuent de s’accumuler dans le champ courant, qui passe en état d’erreur rouge
- Même en se déplaçant manuellement champ par champ pour saisir chaque chiffre, une erreur
field requiredapparaît à la fin
- Une tentative de modifier directement les valeurs du DOM dans les outils de développement n’a révélé aucune valeur de formulaire visible, et aucune erreur n’était enregistrée dans la console Web
- Le résultat était identique avec une autre adresse e-mail ou une fausse adresse comme
test@example.comexample.comest un domaine réservé selon la RFC 6761
Écarter les pistes navigateur et système d’exploitation
- Au départ, on pouvait soupçonner que la combinaison Firefox et Linux n’était pas prise en charge, ou que le CAPTCHA échouait
- Juste avant l’apparition du formulaire de code de vérification, une connexion est établie vers
eu-api.friendlycaptcha.eu - Le document officiel des prérequis ne liste que Windows et macOS comme systèmes d’exploitation pris en charge
- En revanche, la documentation sur les clés de sécurité indique que Linux et Firefox sont également pris en charge
- Juste avant l’apparition du formulaire de code de vérification, une connexion est établie vers
- La même erreur s’est produite dans les 6 combinaisons d’environnements suivantes
- Firefox, Chromium et Chrome sous Linux
- Firefox, Safari et Chrome sous macOS
- Sur un ordinateur portable professionnel, la saisie faisait automatiquement passer au champ suivant, et l’erreur
Code entered is incorrect, indiquant un code erroné plutôt qu’un code vide, s’affichait correctement - Sur le Mac d’un ami, les trois navigateurs acceptaient aussi le code de vérification
- Il n’était pas possible de dépendre d’un ordinateur fourni par l’employeur pour interagir durablement avec des services publics ; même en s’inscrivant depuis l’ordinateur professionnel, il restait possible de ne pas pouvoir se connecter depuis l’ordinateur portable personnel
Une structure de support qui empêchait même de signaler le problème
- Le support officiel n’était proposé que via un formulaire Web, lequel exigeait lui aussi de saisir d’abord un code de vérification par e-mail
- La FAQ précise que le support des organisations participantes est fourni pendant les heures ouvrées uniquement via la création d’un ticket en ligne
- À part l’adresse postale de la Chancellerie fédérale suisse, aucun e-mail ni numéro de téléphone n’était disponible
- La fonction de feedback permettant de laisser des compliments, critiques ou demandes à AGOV exigeait elle aussi une connexion avec AGOV ou un compte équivalent
- Les utilisateurs qui échouaient à la vérification par e-mail se retrouvaient dans une dépendance circulaire : ils ne pouvaient pas signaler le problème à cause de la même procédure de vérification
-
AGOV Access et appareils pris en charge
- L’application Android AGOV Access avait une note de 1,4, mais les avis Google Play ne faisaient pas apparaître le même problème de code de vérification
- De nombreux avis demandaient la prise en charge de GrapheneOS, système d’exploitation Android dérivé axé sur la sécurité et la confidentialité
- Selon la FAQ officielle, l’application ne fonctionne pas parce que le framework renforcé de protection contre les modifications non autorisées n’est pas compatible avec GrapheneOS
- La Chancellerie fédérale a demandé au fournisseur d’assurer la compatibilité
- Actuellement, le second facteur pour l’inscription et la connexion est soit un smartphone iOS·Android standard autorisé, soit une clé de sécurité ; dans les deux cas, il faut d’abord passer la vérification par e-mail
La cause trouvée dans le JavaScript
- La page chargeait peu de ressources, mais le fichier JavaScript principal, minifié sans être obfusqué, pesait 2,4 Mo et dépassait 100 000 lignes une fois déminifié
- Une recherche de la chaîne
field requireda permis de trouver la logique qui définit l’état du code de vérification- Si la variable du code de vérification n’existe pas, l’état est défini sur
REQUIRED - Si sa longueur diffère de la longueur de code requise, elle est traitée comme
WRONG - Si la longueur correspond, l’état
VALIDou un état d’erreur est utilisé selon le résultat de la vérification de l’e-mail par le serveur
- Si la variable du code de vérification n’existe pas, l’état est défini sur
- La fonction
verificationCodeEnteredintercepte les frappes et collecte le code de vérification dans une variable JavaScriptEnterexécute le callback de vérificationBackspaceefface la valeur courante- Les flèches et
Tabdéplacent le focus entre les champs de saisie - Les touches ordinaires sont converties en nombre via
Number(S.key), puis stockées dans le code - Les touches comme
Control,Meta,Shift,vetrsont renvoyées sans traitement
- Comme les valeurs du DOM ne sont pas lues lors de la soumission du formulaire, modifier les champs de saisie avec les outils de développement ou une extension de navigateur ne se répercute pas dans l’état géré séparément par JavaScript
Pourquoi les chiffres étaient bloqués uniquement en AZERTY
- La disposition française standard AZERTY nécessite la touche Shift pour saisir des chiffres
- Comme le code ignorait la saisie de Shift, il était impossible en AZERTY d’enregistrer les chiffres eux-mêmes comme code de vérification
- L’ordinateur professionnel utilisait une disposition anglaise QWERTY, et aucune des personnes ayant aidé à vérifier le problème n’était française
- Résultat : parmi les appareils testés, seuls les deux ordinateurs portables personnels semblaient en panne
- En changeant la disposition du clavier dans le système d’exploitation, la saisie s’est remise à fonctionner sur les ordinateurs portables personnels
- À l’inverse, en basculant un appareil qui fonctionnait vers une disposition française, la même erreur a été reproduite
- Le clavier francophone standard en Suisse appartient à la famille QWERTZ, courante en Europe centrale
- Il permet de saisir efficacement le français et l’allemand, et ne nécessite pas Shift pour les chiffres, si bien que la même erreur n’apparaît pas
- D’après l’Office fédéral de la statistique suisse, environ 171 000 résidents en Suisse ont la nationalité française, sans compter les travailleurs frontaliers qui doivent interagir avec l’administration suisse
Les limites de l’enquête avant la publication du code source
- Selon la FAQ AGOV, le code source d’AGOV doit être publié en décembre 2026 afin de satisfaire aux exigences légales
- L’article 9 de l’EMBAG impose aux organismes fédéraux de publier le code source des logiciels qu’ils développent eux-mêmes ou font développer pour accomplir leurs missions
- Des exceptions s’appliquent lorsque les droits de tiers ou des raisons de sécurité empêchent ou limitent la publication
- Le périmètre publié couvrira la version d’AGOV ayant atteint les objectifs du projet, notamment AGOV e-ID Verifier ; les versions ultérieures seront publiées avec les notes de version préparées après leur sortie
- Même si certains services utilisent déjà AGOV comme connexion obligatoire, le code source n’est pas encore publié, ce qui rendait difficile pour les utilisateurs de signaler directement le bug aux développeurs ou de partager des contournements
Ce que l’inscription a révélé sur l’étendue de la vérification d’identité
- Après avoir changé la disposition du clavier, l’adresse e-mail a été vérifiée et l’inscription finalisée avec une clé de sécurité
- Lors de l’inscription, le nom, le numéro de téléphone et la date de naissance ont été saisis, mais ces informations n’ont pas été vérifiées
- À l’étape d’inscription de base, seules deux choses ont été vérifiées
- L’adresse e-mail existe réellement
- Le second facteur est soit une clé de sécurité d’un modèle autorisé, soit l’application AGOV Access exécutée sur un appareil Android·iOS autorisé
- AGOV est robuste contre la prise de contrôle de compte par phishing à distance, mais à l’étape d’inscription de base, il n’empêche pas quelqu’un de créer un compte en utilisant le nom et les informations d’identité d’une autre personne
- D’après des vérifications supplémentaires, une vérification d’identité est nécessaire pour accéder aux services classés comme sensibles
- Juste après l’inscription, aucun service de ce type n’avait encore été consulté
- Le bug a été signalé via le formulaire de support, mais aucune réponse n’a été reçue
Enseignements de conception
-
Une conception fragile de la saisie et du support
- Créer une interface sophistiquée avec 6 champs de saisie et une logique JavaScript complexe n’est pas robuste
- Il vaut mieux utiliser un seul champ de saisie natif du navigateur et ne styliser que son apparence avec CSS
- Si la logique du formulaire est entièrement séparée du DOM, les valeurs du DOM ne peuvent pas être lues à la soumission, et les utilisateurs avancés comme les extensions de navigateur ne peuvent pas modifier la saisie
- Lorsqu’il n’existe qu’un seul canal de support, il n’y a plus aucun moyen de contact si ce canal lui-même tombe en panne ; il faut donc un deuxième canal, comme l’e-mail ou le téléphone
- Appliquer la même logique de connexion au produit principal et au canal de support fait perdre les signalements de bugs des utilisateurs qui ne peuvent pas se connecter
- C’est aussi pour cette raison que de nombreux services Internet placent leur page de statut sur un domaine séparé
- Mettre les demandes de support derrière une vérification par e-mail peut réduire le spam, mais réduit aussi les signalements d’incidents par de vrais utilisateurs
- Publier le code source seulement après avoir rendu l’usage obligatoire dans certains systèmes limite la résolution des problèmes par les utilisateurs et le partage de bugs ou de contournements
- La publication légale du code source n’est pas qu’une case de conformité : elle est aussi utile pour enquêter sur de vrais incidents
-
L’open Web a aidé l’enquête
- Comme la logique JavaScript concernée n’était pas obfusquée, quelques recherches de chaînes ont suffi à trouver la cause
- Aucun décompilateur avancé ni LLM coûteux n’était nécessaire
- Si le code avait été obfusqué ou compilé en WebAssembly, comprendre la cause aurait pris beaucoup plus de temps
- Comme le code n’était pas distribué uniquement sur des systèmes d’exploitation fermés approuvés mais fourni sur l’open Web, il a pu être téléchargé et analysé, même sous forme minifiée
-
Les conditions qui ont permis d’identifier la cause
- La comparaison de plusieurs ordinateurs portables utilisant différentes dispositions de clavier a permis d’écarter tôt les hypothèses de problème propre à un navigateur ou au réseau
- En revanche, la collecte initiale de preuves a pris du temps, car il a fallu capturer systématiquement les écrans de chaque combinaison de navigateur pour confirmer qu’il ne s’agissait pas d’une erreur utilisateur
1 commentaires
Avis sur Lobste.rs
L’une des pratiques que je déteste le plus sur Internet, c’est quand un site intercepte les frappes au clavier pour les traiter à sa guise au lieu de simplement les laisser au navigateur
Les sites qui interdisent le copier-coller dans les champs de mot de passe sont bien plus courants, mais cela relève de la même catégorie, et c’est peut-être même pire
En général, cela ne fait qu’ajouter de la complexité pour des raisons artificielles
Le système qui met un champ de saisie par caractère est une véritable plaie
Une entreprise l’a adopté parce que ça avait l’air cool, et maintenant tout le monde implémente sa propre version
Même sans lire attentivement, l’utilisateur comprend tout de suite qu’il ne s’agit pas d’un champ de mot de passe
Comme cas connexe, il y a ce bug qu’avait Medium, qui empêchait de saisir le caractère 'Ś'
J’ai réfléchi à d’autres implémentations, mais au final je ne trouve pas de meilleure solution qu’un simple
<input type="text" />J’hésiterais même à trop le décorer en CSS au point qu’il ne ressemble plus à un champ de saisie normal. On pourrait aussi dupliquer la valeur dans de grandes cases, mais il faudrait alors répondre à toutes sortes de problèmes, comme le cas où l’utilisateur saisit plus que la longueur autorisée, et le bénéfice ne me paraît pas suffisant pour justifier l’effort. Au mieux, je changerais la police et la taille du champ
1224au lieu de1234La correction la plus rapide consiste à cliquer sur le deuxième
2puis à appuyer sur3, mais on ne peut pas faire ça avec du HTML+CSS seul<input type="text" pattern="[0-9]+" minlength=6 maxlength=6>et de lui appliquer un espacement de lettres inhabituel pour le faire ressembler visuellement à six casesUne autre approche plus simple serait de laisser l’utilisateur saisir dans un seul champ texte, puis de faire dessiner en JavaScript six cases ailleurs dans le DOM, mises à jour à chaque touche via l’événement
inputIl est difficile de savoir laquelle des deux options serait la meilleure pour l’accessibilité. Du point de vue d’un lecteur d’écran, la seconde — un
<input>ordinaire avec un<canvas alt="">décoratif — pourrait même être préférable, tout en évitant de casser la navigation au clavier. Mais pour les utilisateurs qui emploient d’autres aides que les lecteurs d’écran, masquer visuellement le<input>pourrait devenir une catastrophe en matière d’accessibilité, donc je serais très prudentComme beaucoup de services, on peut aussi fournir à la fois le code et un lien d’activation dans l’e-mail
Cela peut résoudre le même problème
On peut considérer cela comme un cas exceptionnel, mais l’accessibilité consiste précisément à bien gérer ce genre d’exceptions
Tridactyl a exactement le même problème : https://github.com/tridactyl/tridactyl/issues/3257
Il a été signalé pour la première fois en 2019, donc avec cette histoire ils auront peut-être la honte nécessaire pour enfin le corriger
Voilà encore une preuve qu’il faut bien plus d’efforts pour fabriquer un site web cassé ou lent qu’un site qui fonctionne simplement