Praktischer Leitfaden zur Absicherung von B2B-SaaS-Registrierungen
Letzten Monat kam ein B2B-SaaS-Kunde mit einem vertrauten Problem zu uns: Registrierungen wirkten oberflachlich normal, aber kostenlose Credits verschwanden schnell. Die Analyse der Logs offenbarte einen koordinierten Angriff — Dutzende Registrierungen aus denselben /24-Subnetzen, rotierende Wegwerf-E-Mails und ein Angreifer, der Infrastruktur uber mehrere Fake-Accounts wiederverwendete.
Dieser Artikel beschreibt die Verteidigungs-Stack, die wir empfohlen haben. Namen und Kennungen sind anonymisiert, der Ablauf ist produktionsreif.
Was den Angriff erleichterte
Drei Faktoren spielten dem Angreifer in die Hand:
- Alle kostenlosen Credits bei der Registrierung — keine Reibung, keine Verifizierung, sofortiger Wert.
- Keine Geratebindung — derselbe Browser-Fingerprint konnte sich immer wieder registrieren.
- IP-Prufungen fehlten oder waren falsch konfiguriert — hinter Cloudflares Proxy (orange Wolke) las die App Proxy-IPs statt der echten Besucheradresse.
Registrierungssicherheit ist weniger eine Silberkugel als das Schichten von Signalen, die sich gegenseitig verstarken.
Prioritat 1: Die echte IP-Adresse lesen
Wenn Ihre App hinter Cloudflare mit aktiviertem Proxy lauft (orange Wolke), reichen req.ip oder X-Forwarded-For allein nicht. Cloudflare sendet die echte Besucher-IP im Header CF-Connecting-IP.
function getClientIp(request: Request): string {
const cfIp = request.headers.get("cf-connecting-ip");
if (cfIp) return cfIp;
const forwarded = request.headers.get("x-forwarded-for");
if (forwarded) return forwarded.split(",")[0].trim();
return "0.0.0.0";
}
Jede nachgelagerte Prufung — Rate Limits, IP-Reputation, Sperrung — hangt davon ab, diesen ersten Schritt richtig zu machen.
Prioritat 2: IP bei der Registrierung bewerten
Fuhren Sie die Veille IP Reputation API asynchron wahrend der Registrierung aus. Blockieren Sie die HTTP-Antwort moglichst nicht darauf; stellen Sie die Prufung in die Warteschlange und handeln Sie innerhalb von Sekunden.
const API_KEY = process.env.VEILLE_API_KEY!;
const BASE_URL = "https://api.veille.io/v1";
async function scoreIp(ip: string) {
const response = await fetch(
`${BASE_URL}/intelligence/ip?query=${encodeURIComponent(ip)}`,
{ headers: { "x-api-key": API_KEY } }
);
return response.json();
}
Der threat_score aggregiert erkannte Signale:
| Score | Bedeutung |
|---|---|
| 0 | Saubere Wohn- oder Geschafts-IP |
| 1–25 | Geringe Signale (Rechenzentrum, VPN) |
| 25–50 | Moderates Risiko (mehrere Signale) |
| 50+ | Hohes Risiko (Tor, bekannter Missbraucher, Proxy) — sperren oder Extra-Verifizierung |
In den Logs unseres Kunden gruppierten sich Angreifer-IPs in /24-Bereichen mit Scores uber 50. Das Sperren des Subnetzes nach wiederholtem Missbrauch — nicht nur der einzelnen IP — reduzierte das Volumen schnell.
Prioritat 3: FingerprintJS integrieren
Installieren Sie FingerprintJS auf Ihren Registrierungs- und Login-Seiten. Speichern Sie die visitorId bei jedem Versuch.
import FingerprintJS from "@fingerprintjs/fingerprintjs";
async function getFingerprint(): Promise<string> {
const fp = await FingerprintJS.load();
const result = await fp.get();
return result.visitorId;
}
Dann Rate Limits auf IP und Fingerprint anwenden:
- Nach 5 fehlgeschlagenen Registrierungs- oder Login-Versuchen derselben IP oder desselben Fingerprints → Sperre 24 Stunden.
- Beide Werte bei jedem Versuch loggen, um im Back Office zu pivotieren.
Prioritat 4: E-Mail asynchron validieren
Wegwerf-E-Mails stoppen keinen entschlossenen Angreifer, filtern aber einen grossen Teil des Low-Effort-Missbrauchs. Rufen Sie die Veille Email Validation API parallel zur IP-Prufung auf:
async function validateEmail(email: string) {
const response = await fetch(
`${BASE_URL}/intelligence/email?query=${encodeURIComponent(email)}`,
{ headers: { "x-api-key": API_KEY } }
);
return response.json();
}
// Im Registrierungs-Handler:
const [ipResult, emailResult] = await Promise.all([
scoreIp(clientIp),
validateEmail(email),
]);
if (emailResult.disposable || emailResult.risk_score > 70) {
await blockIpTemporarily(clientIp, "disposable_email");
return { error: "Registrierung blockiert" };
}
if (ipResult.threat_score >= 50) {
await blockIpTemporarily(clientIp, "high_threat_ip");
return { error: "Registrierung blockiert" };
}
Fuhren Sie diese Prufungen nach Formularannahme aber vor der Credit-Vergabe aus. Schlagt ein Signal fehl, sperren Sie die IP fur ein konfigurierbares Zeitfenster und geben Sie einen generischen Fehler zuruck.
Prioritat 5: Fingerprint an E-Mail-Verifizierung binden
Ein Konto erstellen ist nicht dasselbe wie zu beweisen, dass Sie die Inbox kontrollieren. Verlangen Sie E-Mail-Verifizierung, bevor Credits nutzbar sind.
Der kritische Schritt, den die meisten Teams auslassen: Der Fingerprint bei der Registrierung muss mit dem Fingerprint beim Klick auf den Verifizierungslink ubereinstimmen.
// Bei Registrierung — ausstehende Verifizierung speichern
await db.pendingVerifications.create({
email,
fingerprintSignup: fingerprint,
ipSignup: clientIp,
token: verificationToken,
expiresAt: addHours(new Date(), 24),
});
// Bei Verifizierung — Fingerprint vergleichen
const pending = await db.pendingVerifications.findByToken(token);
if (pending.fingerprintSignup !== currentFingerprint) {
await flagAccount(pending.email, "fingerprint_mismatch");
return { error: "Verifizierung fehlgeschlagen" };
}
await activateAccount(pending.email);
Eine Abweichung bedeutet nicht immer Betrug — Nutzer wechseln Gerate — aber wiederholte Abweichungen von Hochrisiko-IPs sind ein starkes Signal.
Prioritat 6: Nicht mehr alle Credits bei der Registrierung vergeben
Kostenlose Credits sind der ROI des Angreifers. Verteilen Sie Wert auf Aktionen, die Bots schwer automatisieren konnen:
| Meilenstein | Credits | Warum |
|---|---|---|
| Konto erstellt | 0 | Kein sofortiger extrahierbarer Wert |
| E-Mail verifiziert | +10 | Beweist Inbox-Kontrolle |
| Onboarding abgeschlossen | +25 | Erfordert echte Produktinteraktion |
| Social Share bestatigt | +15 | Erhoht Reibung und Audit-Trail |
Beispiel-Flags im Back Office:
interface UserCredits {
emailVerified: boolean; // +10 Credits
onboardingCompleted: boolean; // +25 Credits
sharedOnSocial: boolean; // +15 Credits
}
function getAvailableCredits(user: UserCredits): number {
let credits = 0;
if (user.emailVerified) credits += 10;
if (user.onboardingCompleted) credits += 25;
if (user.sharedOnSocial) credits += 15;
return credits;
}
Bots optimieren den schnellsten Weg zu Credits. Ein Onboarding mit echten API-Aufrufen, Konfigurationsentscheidungen oder einem kurzen Tutorial bricht skriptierte Ablaufe.
Gesamtuberblick: Registrierungsablauf
Nutzer sendet Registrierungsformular
│
▼
CF-Connecting-IP lesen
│
▼
Fingerprint- + IP-Rate-Limits prufen ──► gesperrt? → 429, loggen
│
▼
Konto erstellen (0 Credits)
│
├──► async: IP-Reputation
└──► async: E-Mail-Validierung
│
▼
Bedrohung erkannt? → IP sperren, Konto markieren
│
▼
Verifizierungs-E-Mail senden (Registrierungs-Fingerprint speichern)
│
▼
Link-Klick → Fingerprint passt? → +10 Credits
│
▼
Onboarding abgeschlossen → +25 Credits
│
▼
Social Share bestatigt → +15 Credits
Sinnvolle Back-Office-Booleans
Geben Sie Ihrem Team Schalter, um ohne Deployment zu reagieren:
block_disposable_emails— Wegwerf-Inboxes bei Registrierung ablehnenblock_high_threat_ips— IPs mitthreat_score >= 50automatisch sperrenrequire_fingerprint_match— Fingerprint-Bindung bei E-Mail-Verifizierung erzwingenrate_limit_by_fingerprint— Fingerprint-basiertes Throttling aktivierengrant_credits_on_signup— wahrend aktivem Angriff auffalselassen
Diese Flags erlauben, Verteidigung wahrend eines Vorfalls zu verscharfen und zu lockern, sobald sich der Traffic normalisiert.
Letzter Ausweg: verlangsamen, nicht ankundigen
Wenn eine IP klar missbrauchlich ist, aber Sie den Angreifer nicht warnen wollen, fuhren manche Teams kunstliche Reibung ein — verzogerte Antworten, CAPTCHA beim zweiten Versuch oder ein falscher SMS-Code, der nie ankommt. Das ist umstritten, sollte letzter Ausweg sein, intern klar geloggt werden und nie legitimen Nutzern gezeigt werden.
Das Ziel ist, die Zeit des Angreifers zu verbrennen, nicht Ihre.
Ergebnisse
Nach Implementierung dieser Stack — echte IP-Extraktion, Veille IP- und E-Mail-Checks, FingerprintJS Rate Limits, fingerprint-gebundene Verifizierung und gestaffelte Credits — sank das Volumen missbrauchlicher Registrierungen des Kunden innerhalb von 48 Stunden deutlich. Legitime Nutzer schlossen das Onboarding ab, ohne die zusatzlichen Prufungen zu bemerken.