ALTCHA: Configuration
ALTCHA spam protection for Shopware 6.7 - all settings with defaults, gibberish detection, disposable e-mail check with domain view, rate limiting and practical examples
ALTCHA Spam Protection: Configuration
This documentation always refers to the latest published release.
Live demo: Try this and other plugins live, no installation, no risk: demo.markus-michalski.net
You find the settings in the Shopware Admin under Extensions > My Extensions > ALTCHA Spam Protection. Every setting can be overridden per sales channel. The sections below carry the card titles as they appear in the admin.
ALTCHA Spam Protection
| Setting | Default | Description |
|---|---|---|
| Enable Spam Protection | on | Master switch for all protection features. When off, neither checks nor widget output run |
| Protect Newsletter Form | on | Protection for newsletter registration forms |
| Protect Registration Form | on | Protection for customer registration, prevents fake accounts |
The contact form has no switch of its own: it is protected as soon as the master switch is on.
ALTCHA Challenge
| Setting | Default | Description |
|---|---|---|
| Enable ALTCHA Widget | on | Shows the "I'm not a robot" checkbox that verifies itself. When off, the ALTCHA check is skipped and the other layers stay active |
| Challenge Cost (PBKDF2 iterations) | 2000 | Work per attempt in the visitor's browser, minimum 1. Higher means harder and slower, for bots and visitors alike |
| Challenge Difficulty (max counter) | 2000 | Upper bound of the search, minimum 2. Each challenge needs between half of it and all of it attempts |
| Challenge Expiry (seconds) | 300 | How long a challenge is valid, between 30 and 3600 |
For safety the plugin internally caps the cost at 100000 and the counter at 1000000. A value of 0 or an empty field falls back to the default.
Honeypot
| Setting | Default | Description |
|---|---|---|
| Enable Honeypot Field | on | Adds an invisible field that traps bots. Legitimate visitors do not notice it |
The field is named fax_number, is moved out of the visible area with position:absolute; left:-9999px (not display:none, which some bots skip) and carries tabindex="-1" and autocomplete="off". A submission with a non-empty field is rejected. A value consisting only of whitespace counts as empty and is accepted.
Minimum Fill Time
| Setting | Default | Description |
|---|---|---|
| Minimum fill time (seconds) | 3 | Submissions arriving faster than this after the form was shown are treated as bots. 0 disables the check |
The form carries a signed render timestamp for this. If the token is missing or not authentic, the shop skips only this layer; the ALTCHA check is not affected. On uncached pages (for example registration) the check works reliably. On HTTP-cached CMS pages (contact, newsletter) a bot scraping the cached page carries an old token and passes this layer; the other layers still apply.
Gibberish Detection
| Setting | Default | Description |
|---|---|---|
| Enable gibberish detection | off | Scores name, subject, message and address fields from 0 (ordinary text) to 100 (keyboard mashing) |
| Suspicious threshold (log only) | 60 | Scores at or above this value are written to the Shopware log but not blocked |
| Reject threshold | 85 | Scores at or above this value are rejected, allowed range 1 to 101. 101 means observe only: nothing is rejected, suspicious scores are still logged |
The scored fields are firstName, lastName, subject and comment as well as billingAddress.street and billingAddress.city, each taken from whichever form submits them. First and last name are therefore checked on registration, contact and newsletter, subject and message on the contact form, street and city on registration. The worst field decides. Log entries start with "ALTCHA gibberish check" and contain action, sales channel, score and reasons, never the text itself.
Recommended rollout: First set the reject threshold to
101, review the log entries for a few days, and only then lower the value.
How the score is built is described under Technical Details.
Disposable E-Mail Addresses
| Setting | Default | Description |
|---|---|---|
| Reject disposable e-mail addresses | off | Rejects addresses from known throwaway-inbox providers outright |
| Additional blocked domains | empty | One domain per line, subdomains included. Lines starting with # are ignored. Also used by content validation |
| Always allowed domains | empty | One domain per line. Overrides the list and the blocked domains, subdomains included, for example for privacy relay services your customers use |
- Matching: The domain itself and every parent domain count:
foo.mailinator.commatches becausemailinator.comis listed,notmailinator.comdoes not. IDN domains are compared in punycode when the PHP functionidn_to_ascii(extensionintl) is available. The fieldemailis checked. - List: A snapshot of the public
disposable-email-domainslist (CC0) ships with the plugin, plus a few built-in extra domains. A check never calls the network. - Refresh: While the check is on globally, a weekly scheduled task downloads the list to
var/mmd_altcha/. If it is on for a single sales channel only, runbin/console mmd:altcha:update-disposable-domainsyourself. A failed download keeps the existing list. - "Blocked domains" view: Below the two text fields the configuration shows a read-only, searchable list of all domains currently blocked (the list plus the own entries of the selected sales channel). It lets you check whether a domain is already covered before adding it. A listed domain that is also under "Always allowed domains" is marked "Always allowed". Loading it requires the admin user to have the permission to read system configuration.
Multiple app nodes: The task refreshes the list only on the node that runs it. With several app nodes or a read-only container image, run the command on every node or rebuild the image, otherwise the other nodes keep using the bundled snapshot.
Content Validation (deprecated)
| Setting | Default | Description |
|---|---|---|
| Enable Content Validation | on | Checks first name, last name, street, city and e-mail address for gibberish and disposable domains. Blocks only with two or more suspicious fields |
This older, coarser check is deprecated in favour of gibberish detection and the disposable e-mail check. It is skipped as soon as one of them is on and will be removed in a future major version. Without those two options it keeps running with the defaults.
Form Rate Limiting
| Setting | Default | Description |
|---|---|---|
| Enable IP-based Rate Limiting | on | Limits form submissions per IP address |
| Max Requests | 3 | Maximum number per time window |
| Time Window (minutes) | 60 | Length of the sliding time window |
The limit applies separately per form (contact, newsletter, registration) and per IP address. Only submissions that passed all previous checks are counted: a rejected submission does not use up quota.
Behind a reverse proxy or CDN the shop only sees the real visitor IP if the trusted proxies are configured in Symfony. Otherwise all visitors share one address and therefore one limit.
Challenge Endpoint DoS Protection
| Setting | Default | Description |
|---|---|---|
| Enable Challenge Rate Limiting | on | Limits requests to /altcha/challenge per IP |
| Max Challenges per IP | 30 | Maximum number per time window |
| Time Window (minutes) | 60 | Time window for the challenge limit |
The limit is deliberately higher than for forms, because a page can load several forms with one challenge each.
Practical examples
Strict protection for a public shop with a lot of spam
Enable Spam Protection: on
Enable ALTCHA Widget: on
Challenge Cost: 4000
Enable gibberish detection: on
Reject threshold: 75
Reject disposable e-mail addresses: on
Max Requests: 2
B2B shop with few but genuine contact requests
Minimum fill time: 5
Enable gibberish detection: on
Reject threshold: 101 (observe only, lower after reviewing the log)
Reject disposable e-mail addresses: off
International shop with many non-German names
Enable gibberish detection: on
Suspicious threshold: 70
Reject threshold: 90
The trigram table behind gibberish detection covers German, English, French, Spanish, Italian and Dutch, so for many other languages you set the thresholds higher.