Who this is for. Whoever plans a member site's launch, with the client and the platform team. Afterwards you know which routes need limits and a captcha, and can agree the numbers before launch rather than during an attack.
The routes to protect
Limits on these belong in front of the site, at the CDN or web application firewall that serves it, where a flood is stopped before it costs a render. Ask the platform team what the site's edge can enforce, and agree the numbers with the client.
| Route | What an attacker wants from it |
|---|---|
POST /login, and POST /oauth/login where OAuth sign-in is used | To guess passwords, or test leaked ones |
POST /register and POST /cdna-api/register | Accounts in bulk, for spam or to fill the client's database |
POST /forgot-password and POST /cdna-api/forgot-password | To flood members' inboxes, and the site's email reputation with them |
Thresholds to start from
There is no platform number to quote here; these are starting values to adjust once real traffic is known:
| Route | Per IP address | Then |
|---|---|---|
| Sign-in | 10 attempts a minute | Delay further attempts, doubling the delay each time |
| Registration | 5 an hour | Delay, and require the captcha |
| Forgotten password | 5 an hour | Delay; never confirm whether the address exists |
Slow down rather than block. An office, a school or a mobile network puts hundreds of people behind one address, and a block on that address locks all of them out because of one of them. A delay that grows with each attempt costs a person a few seconds and an automated attack most of its speed. Where the edge can only block, block for minutes, not days, and answer with a page that says to try again shortly.
The forgotten-password form already answers every address with the same message, "If a user account with the specified email address exists, a password reset link has been sent to it.", so a limit there protects inboxes rather than hiding accounts (Forgotten and reset passwords).
Where the captcha is available
The platform supports Google reCAPTCHA v2, as a checkbox or invisible. Its keys are part of each environment's configuration, set by the platform team, so a captcha that works on production may need keys on staging. On a member site it matters in three places:
| Where | Setting | Default |
|---|---|---|
| Registration, both the form and the API route | reCAPTCHA, in the Users registration settings: Disabled, v2 Checkbox, v2 Invisible | v2 Checkbox |
| Checkout, at payment | Require captcha, in the Checkouts settings: Disabled, Enabled - Checkbox, Enabled - Invisible | Enabled - Checkbox |
| A form built with the Forms module | A captcha element, and the form's Require completed captcha setting | Off until added |
On a Forms module form the element alone is not enough: without Require completed captcha, a submission with no captcha answer is still accepted (Captcha). There is no captcha setting for the sign-in or forgotten-password forms; the limits above are their protection.
On the registration form, render the widget only when the setting is on, inside the form, and the script after it. A failed or missing answer re-renders the form with a 422 and "Recaptcha validation failed":