Zum Inhalt springen

Funktionen

Überblick über das, was das Gateway tatsächlich kann. Bedienung dazu: Admin-UI; Einbau auf der Kundenseite: Formular einbinden.

Ein Mandant ist eine Kundenseite. Angelegt wird er im Admin-UI, alles Weitere hängt daran:

  • Site-Key (site_…) — die öffentliche Kennung im Client-JS. Kein Geheimnis, nur Zuordnung; die Sicherheit liegt komplett serverseitig.
  • Empfänger-Adresse — das Ziel der Formularmails. Kommt nie aus dem Formular, sondern immer aus der Mandanten-Konfiguration.
  • Origin-Allowlist — von welchen Domains Absendungen angenommen werden. Serverseitig geprüft, nicht bloß per CORS.
  • Eigene SMTP-Route oder geteilte Default-Route — jeder Mandant kann über den eigenen Mailserver versenden oder über den der Plattform.
  • Kill-Switch — ein Klick, und der Mandant lehnt sofort alles ab.

Die Formulardaten jedes Mandanten liegen in einem eigenen ORM++-Tenant — Submissions und Nonces sind dadurch hart getrennt.

Das Gateway kennt keine Feldliste. Jedes <input name="…"> wird übertragen und landet im Mailtext; ein neues Feld braucht nur HTML, keine Konfiguration im Gateway. Nur drei Feldnamen sind reserviert: _gw_reply (wird Reply-To), _gw_form (Formular-Kennung) und _gw_hp (Honeypot, setzt das Snippet selbst).

Details und Grenzen: Formular einbinden.

Die Prüf-Pipeline arbeitet „billig zuerst” — was am wenigsten kostet, läuft zuerst, damit ein Angriff früh abbricht:

#SchichtWirkung
1Rate-Limits (global, IP, Site-Key)in-memory, vor allem anderen
2Mandant aktiv? Origin erlaubt?Kill-Switch und Allowlist, serverseitig
3Challenge-TokenHMAC-signiert, TTL 10 min, an Site und Origin gebunden
4Mindest-AusfüllzeitFormular in unter n Sekunden ausgefüllt = Bot
5Honeypotunsichtbares Feld; Treffer täuscht Erfolg vor
6IP-/ASN-ReputationTor-Exits, iptoasn.com, eigene Blocklist
6bHerkunftssperreLänder-/Regionsregel des Mandanten (IPv4 und IPv6)
7Proof-of-Workpro Mandant konfigurierbare Bit-Schwelle
8Nonceatomar eingelöst — ein Token gilt genau einmal (Replay-Schutz)
9Eingabe-HärtungFeld- und Längenlimits, CRLF-Schutz, Reply-To-Validierung
10E-Mail-BlockmusterSperrmuster gegen die Antwortadresse
11Tageskontingentpersistent, zählt wartende und gesendete Mails
12Spam-Scoreab Schwelle Quarantäne statt Versand

Wiederholt auffällige IPs kann das Gateway zusätzlich an eine CrowdSec LAPI melden — die vorgelagerte Firewall sperrt sie dann, bevor der nächste Request überhaupt ankommt (Sicherheit).

Nach außen bleibt das Gateway wortkarg: jede Ablehnung ist 400 {"ok":false,"reason":"rejected"}. Welche Schicht gegriffen hat, steht nur im Log und im Admin — ein Spammer bekommt kein Orakel, an dem er seine Versuche kalibrieren kann. Honeypot-Treffer und Quarantäne sehen für den Client sogar wie Erfolg aus.

Alle Zahlenwerte (PoW-Bits, Spam-Schwelle, Tageskontingent, Mindest-Ausfüllzeit) sind pro Mandant einstellbar und einzeln abschaltbar (0).

Was über der Spam-Schwelle liegt, wird nicht verworfen, sondern quarantänisiert. Im Mandanten-Detail lässt sich jede Absendung freigeben (geht dann in den Versand) oder verwerfen. Falsch positive Treffer kosten damit keine Nachricht.

  • SMTP-Routen mit STARTTLS (587), implizitem TLS (465) oder unverschlüsselt (nur für Relays auf derselben Maschine).
  • Fester Absender pro Route — kein frei wählbares From aus dem Formular. Das schützt die Reputation der Absenderdomain; die Antwortadresse des Einsenders reist als Reply-To.
  • Retry mit Backoff über eine Queue in der Datenbank; ein kurzzeitig nicht erreichbarer Mailserver verliert keine Nachricht.
  • Test-Versand-Button im Admin prüft Verbindung und Login, bevor echte Formulare darauf laufen.
  • Health-Anzeige je Route: letzter Fehler, letzter erfolgreicher Versand.

Optional pro Mandant: Wer das Formular abschickt, bekommt eine kurze Bestätigung an die Adresse, die er selbst eingetragen hat (Feld _gw_reply). Den Text pflegt der Admin als Freitext — er steht so in der Mail, wie er im Admin steht.

  • Aus per Default. Ohne eingeschaltete Option und ohne Antwortadresse im Formular passiert nichts.
  • Ohne die eingesendeten Daten. Die Bestätigung enthält bewusst nur den festen Text. Würden die Formularfelder mitgeschickt, ließe sich über das Formular beliebiger Text an eine beliebige fremde Adresse schicken — das Gateway wäre ein Verstärker.
  • Erst nach bestandener Prüfung. Quarantänisierte Einsendungen lösen keine Bestätigung aus; erst die Freigabe im Admin tut es. Ein mutmaßlicher Spammer erfährt so auch nicht, dass seine Adresse zugestellt werden kann.
  • Zählt auf das Tageskontingent, weil sie an eine vom Absender bestimmte Adresse geht — das begrenzt zugleich das Missbrauchspotenzial.
  • Antworten erreichen den Seitenbetreiber: Reply-To der Bestätigung ist die Empfänger-Adresse des Mandanten.

Pro Mandant lässt sich einschränken, aus welchen Ländern Formulare abgeschickt werden dürfen:

ModusBedeutung
offkeine Einschränkung (Standard)
allownur die gelisteten Länder dürfen absenden
denydie gelisteten Länder dürfen nicht absenden

Gelistet werden Ländercodes (DE, AT, US …) oder Gruppen: DACH (DE/AT/CH), EU (die 27 Mitgliedstaaten), EEA (EU + IS/LI/NO), EUROPE (geografisches Europa inkl. CH, GB, UA).

Die Zuordnung IP → Land kommt aus demselben iptoasn-Dump, der ohnehin täglich für die ASN-Prüfung geladen wird — kein zusätzlicher Dienst, keine Anfrage an Dritte pro Formular. IPv4 und IPv6 werden gleich behandelt; eine Sperre lässt sich also nicht durch einen IPv6-Anschluss umgehen.

Wichtig — unbekannte Herkunft blockt nicht. Lässt sich eine IP keinem Land zuordnen (nicht geroutet, Dump noch nicht geladen oder Download gescheitert), gilt sie als erlaubt — auch im allow-Modus. Andernfalls würde ein gescheiterter Download eines Fremdservers das Kontaktformular komplett stilllegen. Die übrigen Schichten (PoW, Honeypot, Spam-Score, Quarantäne) greifen weiter.

Jeder Geo-Treffer erscheint als blocked-Submission im Admin (mit Grund, z. B. „herkunftsland US gesperrt (modus allow)”) und zählt für die Angriffserkennung mit. Hämmert dieselbe IP dauerhaft dagegen, reißt sie die CrowdSec-Schwelle und wird von der vorgelagerten Firewall gesperrt — bewusst mit niedrigem Gewicht, damit ein einzelner Geschäftsreisender im Ausland nicht sofort in der Firewall landet.

Eigene Sperrliste für IP, CIDR, ASN, E-Mail-Adressen und Länder/Regionen, jeweils mit Notiz. Einträge wirken sofort — sie werden in den Reputations-Speicher gespiegelt und greifen in Schicht 6 der Pipeline. Ein Länder-Eintrag hier gilt global für alle Mandanten; die mandantenspezifische Regel steht im Mandanten-Formular.

Web-UI und API im selben Binary:

  • Benutzer mit argon2id-Passwörtern und Rollen (RBAC, statischer Katalog im Code).
  • API-Keys (fgw_…) für Prozesse ohne Browser — mit Ablaufdatum, Widerruf, read-Scope und eigenem Rate-Limit.
  • Statistiken pro Mandant und Submission-Historie mit Statusfilter.

Details: Sicherheit.

  • Selbst gehostet — die Formulardaten verlassen die eigene Infrastruktur nicht.
  • Client-IPs landen nur als gekürzter SHA-256-Hash in der Datenbank.
  • Keine Cookies, kein Tracking im Client-Snippet, keine Drittressourcen.
  • DSGVO-Export und -Purge pro Kundenseite über die ORM++-Tenant-Registry — Auskunft und Löschung sind eine Operation, kein SQL-Abenteuer.
  • Audit-Log durch Event-Sourcing: jede Submission trägt ihre Statushistorie (received → scored → sent/quarantined → released/discarded).

Dependency-freies Vanilla-JS, ~1,6 KB gzip, minifiziert vom Gateway ausgeliefert. Holt die Challenge, löst den Proof-of-Work in einem Web Worker (mit Fallback auf den Hauptthread), sendet ab und zeigt den Status inline an. Mehrere Formulare pro Seite werden automatisch verdrahtet; ohne JavaScript bleibt das <form> ein normales Formular.

  • Ein Binary — Go-Backend, Svelte-Admin-UI und Client-Snippet sind einkompiliert. Eine Installation besteht aus Binary, config.json und Datenbankdatei.
  • SQLite oder PostgreSQL, umgeschaltet durch eine Konfigurationszeile ohne Codeänderung.
  • CGO-frei ⇒ Cross-Compiling für Linux (amd64/arm64), Windows und macOS ohne Toolchains.
  • Docker-Image (Alpine, non-root, read-only, Healthcheck) und systemd-Betrieb sind dokumentiert.
  • Graceful Shutdown bei SIGINT/SIGTERM, inklusive Hintergrund-Worker.
  • Versions- und Build-Info über -version, GET /api/v1/system/info und den Footer der Web-App.