Les CAPTCHA
Un CAPTCHA visuel exclut par construction. Le RGAA impose une alternative et l'indication de la nature du test : c'est un minimum, pas une garantie d'usage. Démo, code, critères RGAA.
5 critères RGAA en jeu
Essayez-le
1. Le CAPTCHA tenu au mieux
Ce que le RGAA exige — et qui reste insuffisant. Écoutez l’image au lecteur d’écran, puis essayez de passer le test sans la voir.
2. Sans CAPTCHA
Ce qui protège sans exclure. Écrivez-nous : aucun test à passer, ni image à déchiffrer, ni case à cocher, ni calcul.
Ce que les deux formulaires portent réellement
| Avec CAPTCHA | Sans | |
|---|---|---|
| Images à déchiffrer | 0 | 0 |
| Champs de saisie | 0 | 0 |
| Champs sans étiquette | 0 | 0 |
| Champs atteignables au clavier | 0 | 0 |
- Temps de remplissage mesuré (formulaire 2)
- 0 s
- Envois restants pour cette minute
- 3
- Robots refusés par le pot de miel
- 0
Le second formulaire compte un champ de plus que ceux qu’on peut atteindre : c’est le pot de miel. « Remplir comme un robot » fait ce que fait un robot — remplir tout ce que le code contient — et l’envoi est refusé. Envoyez ensuite trois messages d’affilée : le quatrième est refusé, et un envoi parti moins de deux secondes après l’ouverture l’est aussi. Personne n’a eu à prouver quoi que ce soit.
Deux formulaires. Le premier porte un CAPTCHA tenu au mieux — tout ce que le RGAA exige y est : l’alternative qui dit la nature et la fonction du test, le champ étiqueté, de vrais boutons pour réécouter et recharger, une autre voie qui aboutit. Parcourez-le au lecteur d’écran, puis essayez de passer le test sans regarder l’image : c’est là que la conformité montre sa limite.
Le second n’a pas de CAPTCHA, et c’est la sortie que recommande cette fiche. Remplissez-le au clavier : rien ne vous est demandé pour prouver que vous êtes humain. Envoyez trois messages d’affilée, et le quatrième est refusé ; collez un message et envoyez-le en moins de deux secondes, il est refusé aussi. Les défenses existent, elles ne passent simplement pas par vos yeux.
Cette démo existe aussi en page autonome.
L’erreur courante
Croire qu’ajouter une version sonore règle la question.
<!-- À ne pas faire -->
<img src="/captcha.png" alt="captcha" />
<input type="text" name="captcha" placeholder="Recopiez le code" />
<a href="#" onclick="lireLeCode()">🔊</a> Trois fautes tiennent en quatre lignes.
alt="captcha" donne à peu près la nature du test et jamais sa fonction : rien
n’y dit qu’il faut recopier des caractères, ni pourquoi. L’utilisateur entend un
mot technique et ne sait pas ce qu’on attend de lui. L’excès inverse existe
aussi, sur les CAPTCHA maison : un gabarit qui écrit l’alt à partir de la
valeur attendue divulgue la réponse et annule le test.
Le placeholder disparaît dès la première frappe et n’est pas une étiquette :
qui revient sur le champ ne retrouve plus ce qu’on lui demandait.
Le <a href="#"> n’est pas un bouton. Il répond à Entrée, pas
à Espace, s’annonce comme un lien qui ne mène nulle part, et le lecteur
sonore qu’il déclenche n’a souvent aucune commande atteignable au clavier.
Et quand ces trois fautes sont corrigées, le dispositif reste inutilisable pour une partie des gens. L’alternative sonore ne sert ni aux personnes sourdes-aveugles, ni dans un lieu bruyant, ni sans casque dans un bureau partagé ; les extraits déformés qu’on y entend sont souvent plus difficiles à transcrire que l’image ne l’était à lire. Le RGAA s’en satisfait. L’utilisateur, non.
Trois variantes secondaires, toutes fréquentes :
- Le lien « vous n’arrivez pas à lire ce code ? » qui renvoie vers un formulaire de contact protégé par le même CAPTCHA. La boucle est fermée : la personne bloquée reste bloquée.
- Le widget d’un service tiers posé dans une
<iframe>sans titre. Le focus y entre et plus rien ne dit où l’on est. - Le bouton de rechargement qui remplace l’image sans rien annoncer. À l’écran, le code change ; pour un lecteur d’écran, il ne s’est rien passé.
Comment le coder
1. Nommer le test
<img src="/captcha.png" alt="Test de sécurité : recopiez les caractères de l'image pour prouver que vous n'êtes pas un robot." /> Deux exigences se superposent ici, et elles se constatent séparément lors d’un audit. Que l’alternative existe relève du critère 1.1 ; qu’elle dise la nature et la fonction du test relève du 1.4.
La nature, c’est « test de sécurité » ; la fonction, « prouver que vous n’êtes pas un robot ». L’une des deux seule ne suffit pas. Et l’alternative ne doit évidemment pas contenir les caractères à saisir.
Le critère 1.8 — le texte en image — ne s’applique pas ici : le référentiel en fait un cas particulier explicite pour les CAPTCHA. Ne comptez pas la faute deux fois.
2. Étiqueter le champ où l’on retape
<label for="captcha-saisie">Caractères affichés dans l'image</label>
<input id="captcha-saisie" type="text" autocomplete="off" required /> Le 11.1 accepte plusieurs formes d’étiquette : une <label> associée par for/id, un aria-label, un aria-labelledby, un attribut title. Ce que
le référentiel exige, c’est qu’il y en ait une — et son test 11.1.3 encadre le
cas où elle n’est pas visible. Nous recommandons la <label> visible : elle
reste sous les yeux pendant la saisie, là où aria-label ne parle qu’aux
technologies d’assistance. Le placeholder, lui, n’est aucune des conditions du
11.1.
C’est le point le plus souvent manqué sur ce composant, parce que le champ paraît accessoire à côté de l’image.
autocomplete="off" est légitime ici : la valeur change à chaque affichage,
rien ne sert de la proposer à nouveau.
3. La solution d’accès alternatif
Le critère 1.5 demande, au choix, une autre forme de CAPTCHA non graphique ou un autre chemin vers la fonctionnalité protégée.
La première branche est celle que tout le monde prend, et c’est presque toujours la version sonore. La seconde est presque toujours la meilleure : un numéro de téléphone, une adresse de courriel, un guichet. Elle ne demande à personne de réussir un test, et elle fonctionne pour les gens que le son n’aide pas.
Quelle que soit la branche retenue, trois conditions décident de sa valeur réelle :
- Elle est signalée à côté du test, pas enfouie dans une page d’aide.
- Elle aboutit : le chemin de secours ne ramène pas au même CAPTCHA.
- Elle est utilisable au clavier, du bouton jusqu’à la fin de la démarche.
Le seul moyen de le savoir est de l’emprunter réellement.
4. Un composant tiers reste le vôtre
<iframe title="Test de sécurité" src="…"></iframe> « C’est le composant de Google » n’est pas une dérogation : le site qui installe un CAPTCHA en répond. Le bouton qui joue le son, celui qui recharge l’image, la grille d’images qui apparaît en cas de doute — tout cela est du script, et le critère 7.3 demande qu’on puisse le contrôler au clavier comme au pointeur.
Vérifiez aussi qu’aucun script ne retire le focus d’un élément qui vient de le recevoir : le 7.3 le nomme explicitement, et un widget qui se recharge tout seul le fait sans le vouloir.
5. Ce qui protège sans exclure
Un CAPTCHA visuel demande à l’utilisateur de payer le prix d’un problème qui n’est pas le sien. La DINUM le dit sans détour dans sa recommandation de novembre 2024 : les CAPTCHA sont à éviter, et la question à poser d’abord est « a-t-on réellement besoin d’un test, et contre quel risque ? ». Six approches déplacent le prix vers la machine ou vers le serveur ; aucune n’est parfaite, et c’est pour cela qu’on les combine.
Le pot de miel. Un champ que la page cache — à l’œil par CSS, au clavier par
tabindex="-1", aux technologies d’assistance pararia-hidden— et qu’un robot remplissant tout ce qu’il trouve remplit aussi. Rempli, l’envoi est refusé. C’est la plus simple, elle ne coûte rien à personne, et c’est ce que fait le second formulaire de la démo. Sa limite : elle n’arrête que les robots rudimentaires, et un attaquant qui lit le code la contourne en une minute.La limitation de débit. Compter les envois par adresse, par compte, par session, et refuser au-delà. Invisible pour qui envoie un message, décisive contre qui en envoie mille. La démo le fait aussi.
Le temps de remplissage. Un humain met des secondes là où un script met des millisecondes ; un envoi trop rapide est refusé. C’est la forme la plus simple de l’analyse comportementale, et la plus faillible : une navigation au lecteur d’écran ou au commutateur sort des durées moyennes dans l’autre sens, et un seuil trop haut la refuserait.
La preuve de travail. Le navigateur résout un calcul avant l’envoi ; l’utilisateur n’a rien à faire, un robot doit payer ce calcul à chaque tentative. C’est ce que font ALTCHA — auto-hébergé, sans cookie —, Friendly Captcha ou Turnstile. Le composant se pose en une balise et se vérifie côté serveur :
<altcha-widget challengeurl="/api/defi"></altcha-widget>Deux réserves. La DINUM note que faire calculer l’appareil de l’usager n’est pas une bonne pratique d’éco-conception, et pénalise les appareils modestes. Et un service invisible qui doute retombe sur un test visuel : reCAPTCHA invisible n’est pas plus accessible que l’autre le jour où il vous soupçonne, et il envoie les données de l’usager à l’étranger.
Le code envoyé ailleurs. Un code reçu par courriel ou par SMS prouve qu’une personne tient un canal. Il ajoute une étape, mais une étape que tout le monde sait franchir.
La question métier. Un numéro de dossier, une référence de commande, un identifiant d’adhérent : ce que la personne légitime possède déjà, et qu’un robot n’a pas. Et un usager déjà authentifié — FranceConnect, un compte — n’a rien à prouver de plus.
Deux règles d’emploi, quelle que soit l’approche. Ne tester qu’en cas de doute, pas tout le monde à chaque envoi : un test posé sur un formulaire dont personne n’abuse ne protège rien et coûte à tous. Et ne jamais faire reposer la sécurité sur le seul formulaire : le réseau, le pare-feu, l’équilibreur de charge filtrent avant que la page ne s’affiche.
Une précision sur le statut de tout ceci. WCAG 2.2 a ajouté un critère 3.3.8 qui interdit d’imposer un test de fonction cognitive pour s’authentifier. Le RGAA 4.1 s’aligne sur WCAG 2.1 : ce critère n’y figure pas, et rien ici ne l’invente. C’est la direction que prend la norme, pas une obligation actuelle — mais c’est déjà celle de l’administration française.
Au clavier
Un CAPTCHA n’a pas de motif de clavier propre : c’est un formulaire, et l’image n’est pas un arrêt de tabulation.
| Touche | Effet |
|---|---|
| Tab | Va au champ de saisie, puis aux boutons d’écoute et de rechargement. L’image n’est pas focalisable — le focus la saute. |
| Entrée / Espace | Actionne le bouton qui a le focus. Un <a href="#"> répond à Entrée seulement. |
| Entrée dans le champ | Soumet le formulaire, comme dans n’importe quel formulaire. |
Tab vers une <iframe> | Entre dans le composant tiers. Sans title sur l’<iframe>, rien n’annonce où le focus vient d’arriver. |
Ce que le lecteur d’écran restitue
Sur l’image : la nature et la fonction, puis la nature de l’élément — « Test de sécurité : recopiez les caractères de l’image pour prouver que vous n’êtes pas un robot, image ». Sur le champ : son étiquette et sa nature — « Caractères affichés dans l’image, champ de saisie ». La formulation varie d’un lecteur à l’autre, les informations non.
Le diagnostic inverse se fait en quatre écoutes :
- Vous n’entendez que « captcha.png » : l’alternative manque, le constat se pose au 1.1.
- Vous entendez « captcha » : elle existe et ne dit pas la fonction — c’est le 1.4.
- Vous entendez l’étiquette du champ tant qu’il est vide, plus rien ensuite :
c’est un
placeholder, pas une<label>, et c’est le 11.1. - Rien n’annonce qu’une autre voie existe : la solution de rechange a peut-être été codée, elle n’est signalée que pour l’œil.
Checklist
- Une alternative qui dit et la nature et la fonction du test.
- Aucune alternative ne livre la réponse attendue.
- Une étiquette qui satisfait le 11.1 — une
<label>visible de préférence — jamais unplaceholderseul. - Une solution d’accès alternatif signalée à côté du test, et qui aboutit.
- Tous les boutons du dispositif atteignables et activables au clavier.
- Avant tout cela : demandez-vous si un test est vraiment nécessaire.
Les critères RGAA en jeu
- Critère 1.1 — Alternative textuelle des images
Un CAPTCHA est une image porteuse d'information. Sans alternative, un lecteur d'écran annonce un nom de fichier : l'utilisateur ne sait même pas ce qui empêche son formulaire de partir.
- Critère 1.4 — Alternative des CAPTCHA
L'alternative doit dire la nature et la fonction du test sans en livrer la réponse — deux exigences opposées, et « captcha » ne satisfait ni l'une ni l'autre.
- Critère 1.5 — Accès alternatif au CAPTCHA
Sans solution d'accès alternatif, le CAPTCHA ne ferme pas une page mais un service : plus d'inscription, plus de paiement, plus de démarche pour qui ne voit pas.
- Critère 11.1 — Étiquette de champ de formulaire
Le champ où l'on retape le code est un champ de formulaire comme un autre, et c'est le plus souvent celui qu'on laisse à un simple placeholder.
- Critère 7.3 — Contrôle des scripts au clavier
Le bouton « écouter le code », le rechargement, le widget tiers sont scriptés : inatteignables au clavier, ils font de l'alternative une promesse sans effet.
Vérifiez votre composant avec l'extension
Pour aller plus loin
- Critère 1.4 — Alternative des CAPTCHA et 1.5 — Accès alternatif au CAPTCHA : la méthode d’audit, et le fait que ces deux critères ne se déduisent pas du code.
- « CAPTCHA » au glossaire et « image-test » : les définitions qui décident du périmètre — le 1.4 vise les deux, le 1.5 les CAPTCHA seuls.
- Les champs de formulaire : l’étiquetage du champ de saisie, qui est la moitié oubliée de ce composant.
- Le récapitulatif d’erreurs : ce qui se passe après un CAPTCHA raté, et qu’on soigne rarement.
Sources
- DesignGouv — Captcha et accessibilité : les personnes handicapées ne sont pas des robots ! — la recommandation de la DINUM, novembre 2024 : éviter, et les alternatives
- W3C — Inaccessibility of CAPTCHA — l’inventaire des impasses et des solutions de remplacement, par le W3C lui-même
- WebAIM — Screen Reader User Survey #10 — les CAPTCHA en tête des obstacles cités, en 2024 encore
- ALTCHA — une preuve de travail auto-hébergée, sans cookie, annoncée WCAG 2.2 AA
- MDN —
<img>— l’attributaltet ce qu’il porte - WCAG — Understanding 1.1.1 Non-text Content — le cas « CAPTCHA » y est traité nommément
- WCAG — Understanding 3.3.8 Accessible Authentication (Minimum) — où va la norme, dans WCAG 2.2