Account Protection
Deze inhoud is nog niet vertaald.
Account Protection watches the forms your visitors send, with no captcha in the way. It does three things:
- On login, it checks whether the password typed has already shown up in a known leak and tells your app in a header. Your app decides what to do, for example ask for a new password. Only 5 characters of the password’s hash leave the connector.
- It limits login attempts per account, counted by the username typed and not by the IP. A botnet trying one account from a thousand addresses is stopped as one.
- It makes forms refuse robots. A submission that fills a hidden decoy field, or arrives less than 2 seconds after the page loaded, is turned away.
Account Protection is part of the Pro plan.
Turn it on
Section titled “Turn it on”It runs in the connector: the Qlyne proxy or the Cloudflare Worker. With the connector installed:
- In the dashboard, open your site and go to Account Protection, Configuration.
- Pick a protection level (below), then open Advanced and add your routes. With no route, nothing is checked.
- Leave the connector on “Observe only” for a few days and look at the Account Protection Reports. When the numbers make sense, switch to “Enforce” in Connector.
On Cloudflare, the Worker’s routes must cover the login address and the form pages. Tries per account use Cloudflare’s rate limiting, which needs the connector deployed with Wrangler and the wrangler.toml from the dashboard (see Install the connector). The leaked-password warning and forms work with the dashboard install too.
Settings
Section titled “Settings”Login protection
Section titled “Login protection”- Login routes: the address your login form or app posts to, such as
/login,/api/auth/loginor/wp-login.php.*matches anything. Only POST requests are checked. - Username field and Password field: the field names in the form,
emailandpasswordby default. WordPress useslogandpwd. For JSON, use a dot to reach inside:user.email. Forms, multipart and JSON bodies up to 64 KB are read. - Tell my app when a password is in a known breach: on by default. See “What does my app receive?” below.
- Tries per account: 10, 60 or 300 per minute, or no limit. Counted by the username typed, from any IP, over 60 seconds.
- Protected form routes: the page with the form and the address it posts to, such as
/contact*,/signupor/newsletter*. List both: the page gets the hidden fields, the address checks them. - Refuse submissions without the fields Qlyne adds: off by default. When on, a bot that posts without ever opening the page is refused too. Turn it on only when every form on those routes is written in plain HTML.
Use protected forms where people type, such as contact, signup and comments. A one-click form (add to cart) is often sent within 2 seconds and would be refused.
Protection levels
Section titled “Protection levels”A level fills the settings below in one click:
| Setting | Basic | Balanced | Aggressive |
|---|---|---|---|
| Leaked-password warning | on | on | on |
| Tries per account | no limit | 60 per minute | 10 per minute |
| Refuse submissions without the fields Qlyne adds | off | off | on |
A level never touches your routes or field names. If you change a setting by hand, the level shows as Custom.
What visitors see
Section titled “What visitors see”- Too many tries on one account:
429withRetry-After: 60. A browser gets the “Too many requests” page, which reloads on its own. An API call gets{"code": "RATE_LIMITED"}. - A refused form:
403. A browser gets the “Form not sent” page, which says “Go back, check the form and send it again.” An API call gets{"code": "FORM_REJECTED"}. - A leaked password: nothing. The login goes on to your app, and your app decides what to show.
- A protected form page looks the same. Each POST form gets a hidden decoy field and a time stamp, and the page is sent with
Cache-Control: no-store, so every visit gets a fresh stamp. No cookie is set. - In observe mode nobody is stopped. The report counts what would have been limited or refused.
Limits
Section titled “Limits”- The leaked-password warning only works if your app reads the
Qlyne-Leaked-Passwordheader. Qlyne never refuses the login itself. If the check takes longer than 1.5 seconds or the leak service is down, the login goes through without the header. - Protected forms work on forms written in plain HTML in the page. A form built by JavaScript, or sent as JSON, doesn’t get the hidden fields. It goes through unchecked, or is refused when “Refuse submissions without the fields Qlyne adds” is on.
- A bot that loads the page, waits more than 2 seconds and leaves the decoy empty gets through. A challenge on the same page (Bot Management) makes each try cost work.
- Tries per account count every POST to the login route, correct logins included. Many people sharing one account can reach the limit.
- On Next.js, protected forms don’t work: the middleware never sees the page, so it can’t add the fields. Use the form captcha there.
Do you keep the password?
Section titled “Do you keep the password?”No. The connector computes the password’s SHA-1 hash and sends Have I Been Pwned only its first 5 characters. Hundreds of passwords share that prefix, and the match happens inside the connector. The password, the username and the form never go to Qlyne: the report gets only the action and the route. Tries per account are counted under a hash of the username.
Does it work with my form plugin?
Section titled “Does it work with my form plugin?”If the plugin writes a normal <form method="post"> into the page, yes: list the page and the address it posts to. Some plugins send the form with JavaScript to another address, such as /wp-admin/admin-ajax.php on WordPress. That works when the plugin sends every field of the form, hidden ones included, as a form and not as JSON. Try it in observe mode first: if your own submissions show up as “Would refuse form” in the report, leave that route out.
What does my app receive?
Section titled “What does my app receive?”A login with a leaked password reaches your app with the header Qlyne-Leaked-Password: 1, even with the other signals turned off. Check it in your login handler and, once the password is accepted, ask for a new one:
// Nodeconst leaked = req.headers['qlyne-leaked-password'] === '1';// Laravel$leaked = $request->header('Qlyne-Leaked-Password') === '1';Protected forms reach your app with two extra fields, qlyne_hp (empty) and qlyne_ft (the stamp). Your app can ignore them. A refused submission never reaches your app.
What about credential stuffing from many addresses?
Section titled “What about credential stuffing from many addresses?”Tries per account stop many addresses guessing one account. Credential stuffing usually tries many accounts a few times each, which stays under that limit. Two other settings cover it. The leaked-password warning flags logins that use a password from a known breach, which is what stuffing lists are made of. A rate limit per IP on the login route, under WAF & Firewall, catches one address trying many accounts.
Is it on Free?
Section titled “Is it on Free?”No, Account Protection is part of Pro. Every new account gets 7 days of Pro, no card. On Free, the routes you saved stay in the dashboard, but the connector doesn’t apply them until the site is on Pro again. See Plans.
Troubleshooting
Section titled “Troubleshooting”People get “Form not sent”
Section titled “People get “Form not sent””Three causes, from the most common:
- They sent the form in under 2 seconds, as happens with one-click forms. Leave those routes out.
- Only the address the form posts to is listed, not the page, so the form has no stamp. With “Refuse submissions without the fields Qlyne adds” on, it is refused. List the page too.
- The form is built by JavaScript or sent as JSON, with that same setting on. Turn the setting off, or leave the route out.
Real people get 429 on the login
Section titled “Real people get 429 on the login”Every POST to the login route counts, correct logins included, and the count is per account. A shared account can reach 10 per minute. Pick 60 or 300 per minute, or no limit. The count starts over after 60 seconds.
Tries per account do nothing on Cloudflare
Section titled “Tries per account do nothing on Cloudflare”The Worker counts tries with Cloudflare’s rate limiting, which the dashboard install doesn’t set up. Deploy with Wrangler and the wrangler.toml from the dashboard, and check that a Worker route covers the login address.