Privacy-friendly spam protection for Shopware 6 contact and newsletter forms using ALTCHA proof-of-work, honeypot fields, and IP-based rate limiting.
ALTCHA is a self-hosted, privacy-friendly CAPTCHA alternative. Unlike Google reCAPTCHA or hCaptcha:
Instead of image puzzles, ALTCHA uses Proof-of-Work - the user's browser must solve a small computational challenge (SHA-256 hashing). This takes about 1-2 seconds and happens automatically in the background. Bots would need significant computing power to bypass this at scale.
Installation via the Shopware Store is recommended. After purchase, you can install the plugin directly from the backend.
Add the private Composer repository to your shop's composer.json:
{
"repositories": [
{
"type": "composer",
"url": "https://packeton.markus-michalski.net"
}
]
}
Note: Repository credentials will be provided upon license purchase. Private repositories are managed via Packeton.
composer require mmd/altcha-integration
When prompted for authentication, enter the credentials provided with your license.
bin/console plugin:refresh
bin/console plugin:install --activate MmdAltchaIntegration
bin/console cache:clear
Update to the latest version:
composer update mmd/altcha-integration
bin/console cache:clear
Plugin configuration in Shopware Admin:
Settings > Extensions > ALTCHA Spam Protection
| Setting | Default | Description |
|---|---|---|
| Enable Spam Protection | On | Master switch for all protection features |
| Protect Newsletter Form | On | Enable spam protection for newsletter registration forms |
| Setting | Default | Description |
|---|---|---|
| Enable ALTCHA Widget | On | Shows "I'm not a robot" checkbox that auto-verifies |
| Challenge Difficulty (Max Number) | 50000 | Higher = harder challenge, more CPU time required |
| Challenge Expiry (seconds) | 300 | How long a challenge is valid (5 minutes default) |
| HMAC Secret | (empty) | Leave empty to use APP_SECRET. Custom secret for signing challenges |
About Challenge Difficulty:
| Setting | Default | Description |
|---|---|---|
| Enable Honeypot Field | On | Adds invisible trap field that catches bots |
The honeypot is a hidden form field named "website" that legitimate users never see or fill out. Bots that automatically fill all form fields will trigger this trap.
| Setting | Default | Description |
|---|---|---|
| Enable IP-based Rate Limiting | On | Limits form submissions per IP address |
| Max Requests | 3 | Maximum submissions per time window |
| Time Window (minutes) | 60 | Rate limit window (1 hour default) |
| Separate Limits per Sales Channel | Off | Track limits separately for each Sales Channel |
Note: IP addresses are stored as SHA-256 hashes in the database for GDPR compliance. The original IP cannot be reconstructed from the hash.
| Setting | Default | Description |
|---|---|---|
| Enable Challenge Rate Limiting | On | Limits challenge requests per IP to prevent DoS attacks |
| Max Challenges per IP | 30 | Maximum challenge requests per time window |
| Time Window (minutes) | 60 | Rate limit window (1 hour default) |
This prevents attackers from flooding the /altcha/challenge endpoint with requests. When the limit is exceeded, a 429 Too Many Requests response is returned with a Retry-After header.
| Setting | Default | Description |
|---|---|---|
| Log Blocked Spam Attempts | On | Logs blocked submissions for monitoring |
The plugin validates submissions in this order (optimized for performance):
A submission must pass ALL enabled checks to be accepted.
The plugin creates two database tables:
Stores rate limiting data:
ip_hash - SHA-256 hash of IP addressaction - Action identifier (e.g., "contact_form", "newsletter", "challenge")created_at - Timestamp of requestsales_channel_id - Optional Sales Channel associationStores used ALTCHA challenges to prevent replay attacks:
challenge_hash - Hash of the used challengeused_at - When the challenge was usedexpires_at - When to delete this entryA scheduled task runs every 6 hours to clean up:
Task name: mmd_altcha.rate_limit_cleanup
Returns a new ALTCHA challenge for the widget:
{
"algorithm": "SHA-256",
"challenge": "abc123...",
"maxnumber": 50000,
"salt": "xyz789...",
"signature": "sig..."
}
This endpoint is automatically called by the ALTCHA widget when the page loads.
Rate Limiting: This endpoint is protected by separate rate limiting (default: 30 requests/hour per IP) to prevent DoS attacks.
For custom form integrations:
{# Render all protection fields (ALTCHA + Honeypot) #}
{{ spam_protection_fields(context.salesChannel.id) }}
{# Or individually #}
{% if altcha_enabled(context.salesChannel.id) %}
{{ altcha_widget(context.salesChannel.id) }}
{% endif %}
{% if honeypot_enabled(context.salesChannel.id) %}
{{ honeypot_field(context.salesChannel.id)|raw }}
{% endif %}
{# Check if newsletter protection is enabled #}
{% if newsletter_protection_enabled(context.salesChannel.id) %}
{# Show protection fields only for newsletter #}
{% endif %}
This plugin is designed with privacy in mind:
| Aspect | Implementation |
|---|---|
| External Services | None - fully self-hosted |
| Cookies | None |
| User Tracking | None |
| IP Storage | SHA-256 hashed only |
| Data Retention | Automatic cleanup via scheduled task |
| Consent Required | No - no personal data processing |
Important: Since no cookies are set and no data is sent to third parties, you do NOT need to add this plugin to your cookie consent banner.
| Feature | ALTCHA (this plugin) | Google reCAPTCHA | hCaptcha |
|---|---|---|---|
| Self-hosted | Yes | No | No |
| GDPR without consent | Yes | No | No |
| No cookies | Yes | No | No |
| No external requests | Yes | No | No |
| User experience | Auto-verify | Image puzzles | Image puzzles |
| Accessibility | WCAG 2.2 AA | Limited | Limited |
| Server load | Minimal | External | External |
bin/console cache:clearbin/console theme:compileIncrease "Max Requests" or "Time Window" in configuration.
The honeypot relies on bots filling hidden fields. Sophisticated bots might skip hidden fields. Use ALTCHA as primary protection.
Commercial License - Single installation license including:
See LICENSE file for full terms.
For questions and support:
Markus Michalski
Email: support@markus-michalski.net