ALTCHA Spam Protection
ALTCHA proof-of-work spam protection for Sylius forms and the Shop API - channel-configurable protection targets, honeypot, rate limiting, disposable-mail and gibberish checks
ALTCHA Spam Protection
This documentation always describes the latest published version.
Live Demo: Try this and other plugins live — no installation, no risk: demo.markus-michalski.net
Overview
Privacy-friendly spam protection for Sylius storefront forms and the Shop API, based on ALTCHA proof-of-work. No cookies, no fingerprinting, no third-party requests - the visitor's browser solves a small computational puzzle automatically on submit, without visitor input, instead of clicking tiles or reading distorted text.
Which forms are protected is decided per channel in the admin, not globally.
Privacy: Every check runs on your own server. Nothing is sent to an external service, and no cookie or fingerprint is set.
Built-in targets: registration, contact, login, forgotten password, and the checkout sign-in (rate-limit only). The support form (mmd/sylius-support-form-plugin) and the newsletter signup (mmd/sylius-newsletter-management-plugin) are detected automatically when installed and appear in the same admin list. Any other form - from a custom plugin or your own code - can be added through the admin.
graph LR
A["Storefront (Twig hook)"] --> C["ALTCHA check chain"]
B["Shop API (header X-Altcha-Payload)"] --> C
C --> D["Channel settings"]
D --> E{"Result"}
E -->|"accepted"| F["Form / API request is processed"]
E -->|"rejected"| G["Form error / HTTP 422"]
Documentation
| Page | Contents |
|---|---|
| Installation and Operations | Installation, update, cron jobs, uninstall |
| Configuration | Per-channel settings, admin grids, practical examples |
| Content Checks | Disposable-mail and gibberish checks in detail: scope, matching, scoring, rollout |
| Storefront Integration | Placing the widget, Twig function and hooks, theme notes |
| Shop API / Headless | Challenge endpoint, requests, error format |
| Extensibility and Compatibility | Custom targets, service tags, backward compatibility |
| Troubleshooting and FAQ | Common problems, known limitations, frequent questions |
| Technical Details | How the checks run, plugin structure, entities |
Features
| Feature | Description |
|---|---|
| Proof-of-work challenge | PBKDF2 challenge the browser solves automatically on submit without visitor input, signed with a per-channel HMAC secret |
| Single-use proofs | A solved challenge is accepted exactly once (replay protection) |
| Rate limiting | Per form and client address, checked before a challenge is consumed |
| Honeypot field | Invisible field that only a bot fills in |
| Minimum fill time | Signed timestamp rejects submissions sent faster than a human could type |
| Disposable-mail check | Opt-in: rejects addresses from known throwaway-inbox providers, with operator allow/deny overrides |
| Gibberish check | Opt-in: scores free-text fields and rejects keyboard mashing and nonsense text |
| Dual mode | Works identically in the Twig storefront and headless through the Shop API |
| Per-channel configuration | Every setting - targets, difficulty, rate limit, content checks - is scoped to one channel |
Requirements
| Requirement | Version | Notes |
|---|---|---|
| Sylius | ^2.2 | Developed against 2.3; CI runs the full test suite on Sylius 2.2 and 2.3 |
| PHP | ^8.3 | With the sodium extension |
| Symfony | ^7.4 | Symfony 8 is not supported by Sylius 2.x and is therefore excluded |
| Database | MySQL 8 or MariaDB | PostgreSQL is not supported. The migrations are written in MySQL syntax and deliberately abort on other databases. Do not install the plugin in a PostgreSQL project, because the abort would also block all subsequent migrations of your project. Tested against MySQL 8.4, MariaDB is not verified (on DBAL 3 the target_overrides JSON column may additionally need a (DC2Type:json) comment there). |
APP_SECRET |
non-empty | Channel secrets are encrypted with a key derived from it; all application servers must share the same value |
doctrine/dbal |
^3.9 or ^4.0 | Sylius 2.2 pins DBAL 3, Sylius 2.3 allows 4; both run the full test suite. On DBAL 3 the three DATETIME columns carry a (DC2Type:datetime_immutable) comment. Moving that database to DBAL 4 (Sylius 2.2 to 2.3) makes your host's next schema diff list those three columns once, like the Sylius core tables; running the generated migration clears it. |
altcha-org/altcha |
~2.1.0 | Pinned - the bundled widget script and this library speak one protocol |
License
Commercial license: one Sylius installation (all channels, plus its development and staging environments) per license, no redistribution, updates for 12 months from purchase. The bundled ALTCHA widget scripts and the disposable-domain list keep their own licenses (MIT and CC0 respectively).
Support
For licensing, technical questions or bug reports, contact support@markus-michalski.net.