Diese Dokumentation bezieht sich immer auf die aktuellste veröffentlichte Version.
Live Demo: Teste dieses und weitere Plugins live — ohne Installation, ohne Risiko: demo.markus-michalski.net
Alle drei geschützten Formulare laufen durch dieselbe SpamProtectionFacade. Die Reihenfolge ist nach Kosten sortiert: günstige Prüfungen im Speicher zuerst, die kryptographische ALTCHA-Prüfung danach, das Rate Limit mit Datenbankzugriff zuletzt.
Eine abgeschaltete Schicht wird übersprungen. Die Inhaltsvalidierung wird zusätzlich übersprungen, sobald Gibberish-Erkennung oder Wegwerf-E-Mail-Prüfung aktiv ist. Das Rate Limit zählt nur Absendungen, die alle Schichten davor bestanden haben.
Die Registrierung wird über einen Route Decorator geschützt, nicht über ein Event. Die Prüfung läuft deshalb vor dem Anlegen des Kontos.
Kontaktformular und Newsletter laufen über Event-Subscriber auf contact_form.send und NewsletterRegisterEvent (Priorität 500), mit derselben Facade.
Die Gibberish-Erkennung bewertet jedes Textfeld und nimmt den schlechtesten Wert. Der Score ist der Anteil der Buchstaben in auffälligen Wörtern, gewichtet nach der Menge an Beweisen:
| Signal | Beschreibung |
|---|---|
| Buchstabenfolgen | Die Trigramme eines Wortes sind in keiner Sprache der mitgelieferten Tabelle plausibel (Deutsch, Englisch, Französisch, Spanisch, Italienisch, Niederländisch) |
| Tastaturläufe | Fast alle Buchstaben eines Wortes liegen als Nachbarn in einer Tastaturzeile (asdfgh, qwertz) |
| Wiederholungen | Ein Wort besteht aus einer kurzen, wiederholten Einheit (asdfasdf) |
Übersprungen werden URLs, E-Mail-Adressen, Code, Wörter mit Ziffern oder Sonderzeichen und Wörter in nicht lateinischer Schrift. Groß geschriebene Wörter zählen weniger (Namen), und kurze Wörter lösen allein nur selten eine Ablehnung aus. Ein langes, klein geschriebenes Wort aus unmöglichen Buchstabenfolgen kann dagegen schon allein einen hohen Score erreichen. Die Tabelle liegt unter src/Resources/data/gibberish-trigrams.php. Fehlt sie oder ist sie beschädigt, bewertet die Prüfung nichts und protokolliert das einmalig als Warnung.
Die veraltete Inhaltsvalidierung arbeitet dagegen mit festen Regeln (Konsonantenanteil, Tastatursequenzen, Wiederholungen, Konsonantencluster, Buchstabenpaare) auf Vorname, Nachname, Straße und Ort sowie der E-Mail-Domain und blockiert ab zwei auffälligen Feldern.
mmd_altcha_rate_limit_logSpeichert einzelne Zeitstempel für ein gleitendes Zeitfenster.
| Spalte | Typ | Beschreibung |
|---|---|---|
id |
BINARY(16) |
Primärschlüssel |
ip_hash |
CHAR(64) |
HMAC-SHA256-Hash der IP-Adresse |
action |
VARCHAR(50) |
contact_form, newsletter, registration, challenge |
sales_channel_id |
BINARY(16) |
optional, Fremdschlüssel auf sales_channel |
requested_at |
DATETIME(3) |
Zeitpunkt der Anfrage |
Indizes: idx_rate_check (ip_hash, action, requested_at), idx_rate_check_channel (zusätzlich sales_channel_id) und idx_cleanup (requested_at).
mmd_altcha_used_challengeVerhindert Replay-Angriffe.
| Spalte | Typ | Beschreibung |
|---|---|---|
challenge_hash |
CHAR(64) |
Primärschlüssel, Nonce der Challenge |
expires_at |
DATETIME(3) |
Ablaufzeitpunkt |
created_at |
DATETIME(3) |
Erstellungszeitpunkt |
INSERT IGNORE beansprucht eine Challenge atomar: Nur der erste Schreiber gewinnt.
Die Wegwerf-Domain-Liste und die Trigramm-Tabelle liegen als Dateien im Plugin beziehungsweise unter var/mmd_altcha/, nicht in der Datenbank.
Blockierte Versuche stehen im Shopware-Log, nie mit dem eingereichten Text:
[INFO] Spam attempt blocked {"reason":"honeypot_triggered","ip_hash":"...","sales_channel_id":"..."}
[INFO] Registration spam attempt blocked {"reason":"disposable_email","ip_hash":"...","sales_channel_id":"..."}
reason |
Bedeutung |
|---|---|
honeypot_triggered |
Honeypot-Feld war ausgefüllt |
too_fast |
Absendung schneller als die Mindest-Ausfüllzeit |
disposable_email |
Wegwerf-E-Mail-Adresse erkannt |
gibberish |
Gibberish-Score erreicht die Ablehnungsschwelle |
content_validation_failed |
Zwei oder mehr Felder bei der veralteten Inhaltsvalidierung auffällig |
altcha_missing |
Kein ALTCHA-Payload im Request |
altcha_failed |
ALTCHA-Lösung ungültig, abgelaufen oder schon benutzt |
rate_limited |
IP-Rate-Limit überschritten |
APP_SECRET. Ist sie leer, schlägt die Prüfung einer Lösung fehl (geschlossen, die Absendung wird abgelehnt). Dagegen wirft der Challenge-Endpunkt eine Exception und antwortet mit HTTP 500, und die Ausgabe des Token-Felds (form_token_field) löst einen Fehler auf der Formularseite aus.hash_equals() verglichen.MmdAltchaIntegration/
├── Altcha/ # gebündelte altcha-org/altcha-Bibliothek (MIT)
├── Command/UpdateDisposableDomainsCommand # mmd:altcha:update-disposable-domains
├── Controller/Api/BlockedDomainsController # GET /api/_action/mmd-altcha/blocked-domains
├── Core/
│ ├── Checkout/Customer/SalesChannel/RegisterRouteDecorator
│ └── Content/RateLimitLog/ # Entity-Definition, Entity, Collection
├── DisposableEmail/ # Checker, Listenleser, Updater, Katalog, Parser
├── Exception/ # SpamDetectedException, SpamRejection
├── Gibberish/ # Guard, Scorer, Score, TrigramModel
├── Migration/ # Rate-Limit- und Used-Challenge-Tabelle
├── ScheduledTask/ # rate_limit_cleanup, disposable_domains_refresh
├── Service/ # Challenge, Honeypot, FormToken, RateLimit, Facade
├── Storefront/Controller/AltchaChallengeController
├── Subscriber/ # ContactFormSubscriber, NewsletterSubscriber
└── Twig/AltchaExtension # Twig-Funktionen für Templates