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
Ce que le formulaire porte réellement
- Images à déchiffrer
- 0
- Champs de saisie
- 0
- Champs sans étiquette
- 0
- Temps de remplissage mesuré
- 0 s
- Envois restants pour cette minute
- 3
Envoyez trois messages d’affilée : le quatrième est refusé, et personne n’a eu à prouver quoi que ce soit. Le compteur ci-dessus est l’autre défense, et elle est active : un envoi parti moins de deux secondes après l’ouverture du formulaire est refusé lui aussi.
Ce formulaire n’a pas de CAPTCHA — c’est le sujet. 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 à
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é.
Le code, pas à pas
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. Quatre approches déplacent ce prix vers le serveur :
- 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. C’est ce que fait la démo ci-dessus.
- L’analyse comportementale. Le temps de remplissage, l’ordre des champs, la provenance de la requête. Un humain met des secondes là où un script met des millisecondes — la démo ci-dessus en applique la forme la plus simple, le délai minimal avant envoi. C’est aussi la plus faillible : voir plus bas.
- Les jetons de confiance. Le navigateur atteste qu’il a déjà été reconnu comme humain ailleurs, sans nouveau test ni identification.
- 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.
Aucune n’est parfaite, et c’est pour cela qu’on les combine. Elles déplacent le coût sans le supprimer : l’analyse comportementale se trompe sur une navigation au lecteur d’écran ou au commutateur, dont l’ordre des champs et les durées sortent de la moyenne ; la limitation par adresse frappe les connexions partagées ; la question métier ne vaut que pour qui a déjà un dossier. Leur avantage tient en une phrase : aucune ne fait de la vue une condition d’accès.
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.
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
- W3C — Inaccessibility of CAPTCHA — l’inventaire des impasses et des solutions de remplacement, par le W3C lui-même
- 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