Are CAPTCHAs accessible?

Why are the usual strategies used online not accessible and not an option for us? The following CAPTCHA’s are typically used to prevent BOT attacks but are not accessible or fully compliant, and/or have other identified challenges.

CAPTCHAs

Image based CAPTCHA’s

Not accessible as visually impaired people cannot see the images and input the requested information.

Audio CAPTCHA

This will work with the screen readers, as the user can “hear” the word(s), but it can be exploited by smart BOTS and presents the same problem as Image Based CAPTCHA’s for the visually impaired. Here is an audio CAPTCHA that covers it in details.

reCAPTCHA

Uses digitized words but presents the same problem as Image Based CAPTCHA’s for the visually impaired.

Alternative methods

In addition to the above mentioned CAPTCHA’s. the following are also used to prevent attacks.

Common names are not used for attributes

When bots crawl, they typically look for common field names like email address, name etc. This information can be made obscure as a way to deter bots but it would be confusing for our legitimate end users. This option is accessible, but not user friendly.

Hidden input fields

A field that is not required for business can be hidden using Cascading Style Sheets (CSS). A BOT would typically complete this hidden field and upon Submit, we can check if that field has data and if it does we simply reject submission. This option is accessible, but can be hacked.

Random question

Random questions can be asked based on “other” input from the user. For example: What is the second and seventh digit of your phone number. This option is accessible, but can be hacked and there is a significant level of effort required to implement this option.

Email address field/confirmation process

Capturing an email address and implementing an email confirmation process protects against BOT attacks because an email which contains a unique confirmation link is sent to the user immediately after form submission. Successful confirmation via this link verifies the authenticity of the user and persists the data. If the subscription is not confirmed, within a period of time as identified by the business, the data is discarded. This ensures that the data committed to the database is from actual users and not BOT submissions, which in-turn ensures the integrity and accuracy of the data.

Additional information

To further secure the form data, it is recommended that the following additional functionality be implemented as further security.

Hidden input fields

Although as mentioned above, on its own this option is not completely secure but when used with the email address/confirmation process it adds an additional layer to protect data and is not difficult to implement. To ensure accessibility and compliance, this field will be hidden visually and from screen readers, and the input value of this field will be checked before accepting submission of data.

Recommendation

Implementation of the following methods for the web form are recommended to optimize user experience and accessibility, as well as ensure data integrity and accuracy:

If you wish to know more information about CAPTCHAs and alternative methods to prevent BOT attacks we encourage you to visit the Captcha Alternative and thoughts page on the W3C website.

Honeypot technique

Preamble

How the honeypot technique should work:

  • Expose a form field to a bot, but not a human.
  • The field should have a programmatically determinable purpose (such as through the use of a label element that's associated to the input so a bot can figure out what's being asked.
  • That field should be something that the form could be asking for, but isn't, such as a birthdate, or a secondary phone number.
  • A bot should have as much evidence as possible that the field should be filled in, like even adding "required" to the label text, and not embedding a class name like "hidden" or having style="display:none;".
  • Add required attributes to the <input>, then get the browser to ignore it: either remove with JavaScript just before form submission or use the novalidate attribute on the <form> element.
  • In order for humans to avoid filling it in:
    • It should be hidden visually (like using class="sr-only", class="wb-inv")
    • It should be removed form the tab order using tabindex="-1"
    • They should be hidden from screen readers using JavaScript to apply aria-hidden="true" on an ancestor element of the input and label
  • If, after submitting, the server detects a value in that form field, it should ignore the form submission.

Code Example

The following code is the bare minimum needed for this to work. This is a website registration form that requires a username, a password (to be entered twice), and an email address. The Birthday field is a honeypot field.

HTML

<form id="regForm" action="registrationPage" method="POST" novalidate>
	<div>
		<label for="username"></label>
		<input id="username" name="username" aria-describedby="formatforusername" required>
	</div>
	<div>
		<label for="password"></label>
		<input id="password" name="password" required type="password">
	</div>
	<div>
		<label for="repassword"></label>
		<input id="repassword" name="repassword" required type="password">
	</div>
	<div>
		<label for="email"></label>
		<input id="email" name="email" required type="email">
	</div>
	<div>
		<label for="birthday" class="invisibleStuff"></label>
		<input id="birthday" name="birthday" class="hpclass" required>
	</div>
			
	<div>
		<input id="saveBtn" name="saveBtn" value="Register" type="submit">
	</div>
</form>
<script src="user.js">

CSS

.invisibleStuff {
	position: absolute;
	height: 1px;
	width: 1px;
	clip: rect(1px, 1px, 1px, 1px);
	overflow: hidden;
	margin: 0;
}

.hpclass {
	z-index: -5;
	font-size: 0pt;
	position: relative;
	top: -5em;
	height: 0px;
	overflow: hidden;
	width: 0;
	line-height: 0px;
	margin: 0;
	padding: 0;			 
}

Javascript

function hp () {
	let hps = document.querySelectorAll("input.hpclass");
	window["wb-frmvld"] = {"ignore" : "input.hpclass"};  // Cette ligne n'est nécessaire que si la page utilise la validation du BOEW

	for (let i = 0; i < hps.length; i++) {
		hps[i].setAttribute("tabindex", "-1");
		hps[i].classList.add("invisibleStuff");
		hps[i].parentNode.setAttribute("aria-hidden", "true");
	}
}

document.addEventListener("DOMContentLoaded", hp, false);