Dein Kontaktformular funktioniert. Genau das ist das Problem. Keine Woche nach dem Livegang sammelt es SEO-Angebote, Krypto-Gewinnspiele und Nachrichten, die aus nichts als drei Links und dem Wort “hi” bestehen.
Der Reflex ist, ein CAPTCHA davorzuschalten. Bevor du das tust, lohnt es sich zu wissen, was dich das wirklich kostet und dass die Techniken, die am meisten Spam abfangen, für deine Besucher unsichtbar sind.
Was ein CAPTCHA wirklich kostet
Ein CAPTCHA ist nicht kostenlos. Du bezahlst es mit Einsendungen, die nie ankommen.
Wer bei einem Rätsel am ehesten abbricht, sind genau die Leute, die du am wenigsten verlieren willst: jemand mit schlechter Verbindung am Handy, jemand mit Screenreader, jemand, dessen Privatsphäre-Setup die Challenge endlos wiederholen lässt. Diese Leute schreiben dir keine Beschwerde-Mail. Sie gehen einfach, und du erfährst nie, dass es die Nachricht gab.
Der Spam, der wirklich weh tut, kommt derweil trotzdem durch: gezielte Nachrichten, getippt von einem Menschen, der fürs Formularausfüllen bezahlt wird. Lösungsdienste kosten Bruchteile eines Cents pro Rätsel. Du hast also echten Besuchern Hürden aufgebaut und deinen schlimmsten Absendern Kosten im Rundungsbereich verursacht.
Das Ziel ist deshalb nicht “jeden Bot blockieren”. Es geht darum, das massenhafte automatisierte Rauschen unauffällig abzufangen und bei allem anderen vorsichtig zu sein.
Technik 1: Der Honeypot
Ein Honeypot ist ein Formularfeld, das kein Mensch sehen kann. Bots parsen dein HTML und füllen alles aus, was ausfüllbar aussieht. Echte Besucher rühren es nie an, weil es nirgends dargestellt wird, wo sie hinkommen.
<!-- Bots füllen das aus; Menschen sehen es nie -->
<input
type="text"
name="botcheck"
style="position:absolute; left:-9999px;"
tabindex="-1"
autocomplete="off"
aria-hidden="true"
/>
Vier Details in diesem Markup, und jedes davon zählt:
- Aus dem Sichtbereich geschoben, nicht
display:none. Manche Bots überspringen versteckte Inputs gezielt. Es aus dem Viewport zu schieben, ist weniger offensichtlich. tabindex="-1"verhindert, dass Tastaturnutzer in ein Feld tabben, das sie nicht sehen können.aria-hidden="true"verhindert, dass Screenreader es vorlesen. Ohne dieses Attribut ist dein Honeypot ein Barrierefreiheits-Bug: Eine blinde Person hört ein mysteriöses Feld, füllt es aus und wird stillschweigend gefiltert. Das ist das denkbar schlechteste Ergebnis.autocomplete="off"hält den Browser davon ab, es für einen echten Menschen hilfsbereit auszufüllen.
Die Falle, die niemand erwähnt: Der Feldname muss zu dem passen, was dein Backend prüft. Wenn du dir einen eigenen Namen ausdenkst, weiß der Server nichts von einem Honeypot und speichert das Feld einfach als ganz normales Feld. Das Formular sieht gut aus und filtert nichts. Formpaste sucht nach botcheck; was auch immer du nutzt, schau in der Doku deines Anbieters nach, statt zu raten.
Technik 2: Die Zeitprüfung
Menschen brauchen Zeit, um ein Formular auszufüllen. Bots senden sofort ab.
Halte fest, wann die Seite geladen wurde, schick den Wert mit und vergleiche beim Eintreffen:
<input type="hidden" name="_ts" id="form-ts" />
<script>
document.getElementById("form-ts").value = Date.now();
</script>
Der Schwellenwert sollte großzügig sein. Formpaste stuft alles unter drei Sekunden als verdächtig ein. Das ist bewusst niedrig angesetzt. Wer eine vorbereitete Nachricht in ein Ein-Feld-Formular einfügt, ist schnell, und dafür soll niemand bestraft werden. Drei Sekunden erwischen Skript-Einsendungen, ohne einem eiligen Menschen in die Quere zu kommen.
Beachte, was passiert, wenn der Zeitstempel ganz fehlt: Es gibt null Punkte, statt es dem Absender anzulasten. Wer JavaScript deaktiviert hat, ist deshalb noch lange kein Bot.
Technik 3: Link-Dichte
Der meiste Spam existiert, um Links zu transportieren. Sie zu zählen ist billig und erstaunlich wirksam:
const URL_RE = /https?:\/\/[^\s]+/gi;
const links = (text.match(URL_RE) ?? []).length;
Formpaste bewertet das als Kurve statt als harte Kante: zwei Links geben die halbe Punktzahl, drei oder mehr die volle. Ein echter Kunde schickt gelegentlich einen Link, manchmal zwei. Eine Nachricht mit vier Links ist selten jemand, der nach deinen Preisen fragt.
Technik 4: Keywords und strukturelle Muster
Keyword-Matching ist die naheliegendste Technik und die am meisten überschätzte, deshalb braucht sie die engsten Grenzen.
Einzelne Wörter werden an Wortgrenzen gematcht, nicht als Teilstring. Dieses Detail kannst du nicht überspringen. Ein naives text.includes("cialis") ist unkritisch, aber wenn includes("spec") innerhalb von “Spezialist” trifft, ist das genau die Art Bug, die still und leise legitime Post auffrisst. Mehrwort-Phrasen wie "buy backlinks" werden als Teilstring gematcht, weil die Phrase selbst das Signal ist.
Verschleierung wird gesondert behandelt, denn Spammer schreiben v1agra und c4sino:
{ canonical: "viagra", re: /(?<![a-z])v[i1!|]agr[a4@](?![a-z])/i }
Strukturelle Muster erkennen die Form statt des Vokabulars, mit bewusst konservativen Schwellen:
// Schreien: 4+ aufeinanderfolgende GROSSGESCHRIEBENE Wörter mit je 3+ Buchstaben
{ name: "shouting", re: /\b[A-Z]{3,}\b(?:\s+\b[A-Z]{3,}\b){3,}/ }
// Übermäßige Zeichensetzung: 4+ mal dasselbe !, ? oder $ hintereinander
{ name: "excessive_punctuation", re: /([!?$])\1{3,}/ }
Beide sind so eingestellt, dass eine normale Nachricht durchkommt. Ein wütender Satz in Großbuchstaben löst die Schrei-Regel nicht aus, und “ASAP” oder “URL” ebenso wenig, weil Abkürzungen meist einzeln stehen statt in einer Viererkette. Wer “hilfe!!” schreibt, ist unauffällig; vier Ausrufezeichen am Stück sind eine andere Art von Nachricht.
Die Regel, die wichtiger ist als jede einzelne Prüfung
Jetzt kommt der Teil, den die meisten Spam-Filter-Ratgeber auslassen, und er entscheidet darüber, ob ein Filter dir hilft oder dir still und leise Geschäft kostet.
Kein einzelnes schwaches Signal sollte je für sich allein eine Nachricht abweisen.
Jede Prüfung oben produziert False Positives. Echte Menschen schicken Links. Echte Menschen benutzen das Wort “Casino”, wenn sie ein Casino betreiben. Echte Menschen füllen Formulare schnell aus. Wenn eines davon allein zur Ablehnung führt, verlierst du echte Nachrichten, und du erfährst es nie, weil der Absender davon ausgeht, dass du sie bekommen hast.
Die Lösung heißt: bewerten statt urteilen. Jedes Signal addiert Punkte; nur die Summe entscheidet. Das sind die Gewichte, die Formpaste verwendet:
| Signal | Punkte |
|---|---|
| Honeypot ausgefüllt | 100 |
| In unter 3 Sekunden abgeschickt | 40 |
| Dublette einer kürzlichen Einsendung | 40 |
| Link-Dichte | 30 |
| Wegwerf-E-Mail-Adresse | 30 |
| Spam-Keywords | 25 |
| Strukturelle Muster | 25 |
Die Quarantäne-Schwelle liegt bei 100.
Liest man diese Zahlen, wird das Design klar. Keywords allein bringen 25, weit entfernt von 100. Eine Nachricht darf “investment opportunity” enthalten und landet trotzdem in deinem Postfach, weil ein einzelnes schwaches Signal kein Beweis ist. Aber Keywords plus drei Links plus eine Wegwerfadresse ergeben 80, und eine schnelle Einsendung bringt das Ganze auf 120. Jetzt ist es ein Muster und kein Zufall.
Der Honeypot ist die bewusste Ausnahme mit 100 Punkten: Ein unsichtbares Feld füllt kein Mensch versehentlich aus, das ist für sich genommen eindeutig. Wichtig dabei: Er läuft trotzdem über denselben additiven Pfad und nicht über einen Sonderfall im Code. Ein Codepfad, keine Überraschungen.
Quarantäne statt Löschen
Auch ein gut eingestelltes Scoring liegt manchmal daneben. Damit stellt sich die Frage: Was machst du mit einer Nachricht, bei der du dir zu 80 % sicher bist, dass sie Spam ist?
Die falsche Antwort ist, sie zu löschen. Stilles Verwerfen bedeutet: Ein echter Kunde hat dir geschrieben, eine Erfolgsmeldung gesehen und wartet auf eine Antwort, die nie kommt. Diesen Fehler kannst du nicht bemerken. Du kannst ihn nicht messen. Du verlierst einfach das Geschäft und erfährst nie davon.
Die bessere Antwort ist ein Quarantäne-Ordner. Verdächtige Nachrichten werden festgehalten und bleiben sichtbar, statt vernichtet zu werden, sodass ein False Positive einen Klick zum Prüfen kostet statt einen Kunden. Bei Formpaste ist die Quarantäne-Ansicht im kostenlosen Tarif verfügbar (nur lesend), und eine Nachricht zurück ins Postfach freizugeben, was den Absender zugleich auf die Positivliste setzt, ist eine Pro-Funktion.
Egal welchen Anbieter du nutzt, die Frage lautet: Was passiert mit einer Nachricht, die verdächtig aussieht, es aber nicht ist? Wenn die Antwort “sie wird gelöscht” lautet, tauschst du ein unsichtbares Problem gegen ein sichtbares.
Was ohne Server nicht geht
Zwei dieser Dinge brauchen ein Backend, und das sollte man offen sagen.
Rate Limiting braucht gemeinsamen Zustand über Requests hinweg. Formpaste fährt dafür mehrere Ebenen: 5 Einsendungen pro 10 Sekunden pro Formular-Key, 10 pro Minute pro IP, dazu ein anhaltendes Limit pro Key, das ein gleichmäßig statt stoßweise bearbeitetes Formular erwischt. Von einer statischen Seite aus ist davon nichts möglich.
Dubletten-Erkennung muss sich merken, was vorher eingesendet wurde, und das heißt wieder Speicher. Sie ist 40 Punkte wert, weil dieselbe Nachricht mehrfach geschickt zu den stärksten Signalen überhaupt gehört.
Honeypot-Markup und Zeitstempel-Felder kannst du heute in jede statische HTML-Seite einbauen. Scoring, Rate Limiting und Quarantäne brauchen etwas Serverseitiges, und genau dafür gibt es Formular-Backends.
Alles zusammen
Wenn du eine Sache mitnimmst: bewerten, nicht urteilen. Sammle mehrere schwache Signale, addiere sie und handle nur nach der Summe. Und halte die Grenzfälle irgendwo fest, wo du sie sehen kannst, statt sie zu löschen.
Dieser Ansatz fängt die überwältigende Mehrheit des automatisierten Spams ab, kostet deine echten Besucher nichts und scheitert glimpflich, wenn er danebenliegt. Ganz ohne Rätsel.
Wenn du ein Formular in eine statische Seite einbaust und das komplette Setup willst: Die Schritt-für-Schritt-Anleitung für ein Kontaktformular ohne Backend deckt das Markup ab, und die Spam-Filterung ist von Haus aus aktiv.