EMPEDIAcaptcha: Bot-Schutz einbinden

EMPEDIAcaptcha schützt Formulare und Schnittstellen vor automatisierten Anfragen – ohne Rätsel, ohne Cookies und ohne Fingerabdruck. Der Browser löst im Hintergrund eine kleine Rechenaufgabe, Ihr Server prüft das Ergebnis. Den Bereich finden Sie unter „Captcha“, sofern er für Ihre Organisation freigeschaltet ist.

Unsere Vorteile

  • Datenschutz: keine Cookies, kein Browser-Speicher, kein Fingerprinting; keine Weitergabe von Daten an Dritte; Betrieb und Hosting in Deutschland; AVV vorhanden. Damit ist der Dienst DSGVO-konform ausgelegt und braucht keinen Cookie-Banner.
  • Sparsam bei Daten: gespeichert werden nur Tageszähler je Domain und kurzlebige Token-Kennungen – keine IP-Adressen, keine Formularinhalte.
  • Barrierefrei: kein Bilderrätsel, kein Klick – Besucher bemerken die Prüfung nicht.
  • Nachvollziehbar abgerechnet: eine Anfrage ist ein tatsächlicher Aufruf (Aufgabe oder Inhaltsprüfung) – ohne Tricks mit „erfolgreich“ oder „fehlgeschlagen“; Benachrichtigung bei 80 % und 100 % des Kontingents.
  • Alles in einem: Bot-Prüfung, Inhaltsprüfung mit eigenen Regeln und Seitenschutz in einem Produkt.

So funktioniert es

  1. Das Widget holt eine Aufgabe, rechnet sie (meist unter einer Sekunde) und legt ein kurzlebiges Token in das Formularfeld empedia-captcha-token.
  2. Ihr Server schickt das Token zusammen mit dem Secret an /captcha/v1/siteverify.
  3. Antwortet der Dienst mit "success": true, wird die Anfrage verarbeitet; sonst wird sie abgelehnt. Jedes Token gilt genau einmal.
Wichtig: Das Secret gehört nur auf Ihren Server (Umgebungsvariable EMPEDIA_CAPTCHA_SECRET) – nie in den Browser, ins Formular oder in ein Repository. Es wird nur einmal angezeigt; bei Verlust erneuern Sie es unter „Einstellungen“ (das alte gilt noch eine Stunde).

Drei Schutzarten – was brauche ich?

SchutzartWofürWo einrichten
Bot-PrüfungFormulare und Aktionen vor automatisierten Anfragen schützen (Kontakt, Anmeldung, Kommentare, Kauf)Widget einbinden, Token auf Ihrem Server prüfen
Inhaltsprüfung (ab Pro)Spam in Texten, E-Mail-Adressen und IP-Adressen erkennen – auch wenn ein Mensch absendetIhr Server fragt die Schnittstelle check ab; eigene Regeln unter „Regeln“
SeitenschutzDie ganze Domain vorübergehend schützen, z. B. bei AngriffswellenModul auf dem Server, Schalter unter „Seitenschutz“

Die drei lassen sich einzeln nutzen. Für die meisten Websites genügt die Bot-Prüfung; die Inhaltsprüfung ergänzt sie bei Formularen mit viel Spam. Fertigen Code für alle drei finden Sie unter „Beispiele“.

Domain anlegen

Eine Domain ist eine registrierbare Domain mit allen Subdomains, z. B. urbanstudio.de und *.urbanstudio.de. Weitere Domains (z. B. empedia.de) legen Sie separat an – so bleibt auch die Auswertung je Domain getrennt.

1
Domain hinzufügen

Name und die Hosts eintragen (z. B. example.com und *.example.com für alle Subdomains; *.example.com allein erlaubt nicht die Hauptdomain). Alle Hosts müssen zur selben Domain gehören. Auf anderen Hosts funktioniert das Widget nicht.

2
Schlüssel notieren

Der Site-Key kommt ins Formular, das Secret auf den Server.

3
Strenge wählen

„Ausgewogen“ passt für die meisten Formulare. „Streng“ eignet sich für Anmeldung, Registrierung und Zahlung; „Locker“ lässt auch ungewöhnliche Browser durch.

Einbinden: HTML

captcha.empedia.cloud ist unsere Standardadresse für Widget und Schnittstelle. Haben Sie das Whitelabel-Merkmal (ab Paket Business), laufen beide stattdessen über Ihre eigene, bereits verifizierte EMPEDIAcloud-Domain – keine zusätzliche Einrichtung nötig, einfach die Adresse unten durch Ihre eigene ersetzen. Die für Ihre Organisation passende Adresse (automatisch richtig eingesetzt) finden Sie außerdem in der Oberfläche unter „Beispiele“.

<script src="https://captcha.empedia.cloud/captcha/v1/widget.js" async defer></script>

<form method="post" action="/kontakt">
  <input name="email" type="email" required>
  <textarea name="message" required></textarea>
  <div class="empedia-captcha" data-sitekey="ek_site_…" data-action="contact"></div>
  <button type="submit">Senden</button>
</form>

Optionen am Widget: data-action (frei wählbarer Name der Aktion, z. B. login), data-mode (focus = beim ersten Berühren des Formulars, Standard; load = sofort; submit = erst beim Absenden), data-badge="false" blendet den kleinen Hinweis aus.

Prüfen: PHP

Mit dem offiziellen SDK (composer require urbanstudio/empedia-captcha, Packagist) – inklusive Widget-HTML und optionaler Inhaltsprüfung:

<?php
require 'vendor/autoload.php';
use Empedia\Captcha\{Client, Widget};

$captcha = Client::fromEnv(); // EMPEDIA_CAPTCHA_SITEKEY / _SECRET / _BASE

// Im Formular
echo Widget::script($captcha->base());
echo Widget::element($captcha->sitekey(), 'contact');

// Beim Absenden
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $r = $captcha->verify($_POST[Client::TOKEN_FIELD] ?? '', 'contact');
    if (!$r->success) {
        http_response_code(400);
        exit('Bitte erneut versuchen.');
    }
    // … Formular verarbeiten
}

Nicht erreichbarer Dienst: new Client(..., ['failOpen' => true]) lässt Anfragen durch (Standard: ablehnen). Ohne Composer geht es auch ohne Zusatzbibliothek, nur mit cURL:

<?php
function empedia_captcha_verify(string $token, string $action = ''): bool {
    if ($token === '') return false;
    $fields = ['secret' => getenv('EMPEDIA_CAPTCHA_SECRET'), 'response' => $token];
    if ($action !== '') $fields['action'] = $action;
    $ch = curl_init('https://captcha.empedia.cloud/captcha/v1/siteverify');
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($fields)]);
    $out = curl_exec($ch);
    if ($out === false) return false;
    $r = json_decode($out, true);
    return is_array($r) && ($r['success'] ?? false) === true;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!empedia_captcha_verify($_POST['empedia-captcha-token'] ?? '', 'contact')) {
        http_response_code(400);
        exit('Bitte erneut versuchen.');
    }
    // … Formular verarbeiten
}

Prüfen: Node.js

Mit dem offiziellen SDK (npm i @urbanstudio/empedia-captcha, npm) – mit fertiger Express-Middleware:

import { EmpediaCaptcha } from '@urbanstudio/empedia-captcha';
const captcha = EmpediaCaptcha.fromEnv(); // EMPEDIA_CAPTCHA_SITEKEY / _SECRET / _BASE

// Express: prüft das Token automatisch (Feld "empedia-captcha-token" oder Header X-Captcha-Token)
app.post('/kontakt', captcha.middleware({ action: 'contact' }), handler);

// oder manuell
const r = await captcha.verify(req.body['empedia-captcha-token'], 'contact');
if (!r.success) return res.status(400).end();

Ohne Zusatzbibliothek, nur mit fetch:

async function verifyCaptcha(token, action) {
  if (!token) return false;
  const body = new URLSearchParams({ secret: process.env.EMPEDIA_CAPTCHA_SECRET, response: token, ...(action ? { action } : {}) });
  try {
    const r = await fetch('https://captcha.empedia.cloud/captcha/v1/siteverify', { method: 'POST', body, signal: AbortSignal.timeout(5000) });
    return (await r.json()).success === true;
  } catch { return false; }
}

Prüfen: Python

Mit dem offiziellen SDK (pip install empedia-captcha, PyPI):

from empedia_captcha import EmpediaCaptcha
captcha = EmpediaCaptcha.from_env()  # EMPEDIA_CAPTCHA_SITEKEY / _SECRET / _BASE

r = captcha.verify(request.form.get("empedia-captcha-token"), "contact")
if not r.success:
    abort(400)

Ohne Zusatzbibliothek, nur mit requests:

import os, requests

def verify_captcha(token, action=None):
    if not token:
        return False
    data = {"secret": os.environ["EMPEDIA_CAPTCHA_SECRET"], "response": token}
    if action:
        data["action"] = action
    try:
        r = requests.post("https://captcha.empedia.cloud/captcha/v1/siteverify", data=data, timeout=5)
        return r.ok and r.json().get("success") is True
    except requests.RequestException:
        return False

WordPress

Der einfachste Weg ist das Plugin EMPEDIA Shield: Installieren Sie es und aktivieren Sie unter Bot-Schutz den Bot-Schutz (EMPEDIAcaptcha ist dort als Modul enthalten, ein separates Plugin gibt es nicht). Für eigene Lösungen finden Sie in der Oberfläche unter „Beispiele → Bot-Prüfung → WordPress“ einen kleinen Baustein (Kommentare), den Sie als mu-plugin ablegen. Das Secret tragen Sie in der wp-config.php ein: define('EMPEDIA_CAPTCHA_SECRET', '…');.

Nicht nur Formulare

Für Fetch-/API-Aufrufe ohne Formular: const token = await EmpediaCaptcha.execute({ sitekey: 'ek_site_…', action: 'api' }); und das Token als Header mitschicken; der Server prüft es wie oben. Dasselbe gilt für Server-zu-Server-Aufrufe mit den Bibliotheken oben.

Inhaltsprüfung (ab Stufe „Pro“)

Zusätzlich zum Token kann Ihr Server die Daten einer Anfrage bewerten lassen: POST /captcha/v1/check mit sitekey, secret und fields (ip, email, name, username, subject, message, honeypot). Optional prüft response (das Captcha-Token derselben Anfrage) mit. Die Antwort enthält verdict (allow durchlassen, review prüfen/in den Spam-Ordner, block ablehnen), einen Risikowert und die Gründe.

Geprüft wird gegen die täglich aktualisierten Sperrlisten von StopForumSpam (IPv4, IPv6 als /64-Netz, E-Mail-Adressen, Benutzernamen, Spam-Domains), gegen Ihre eigenen Regeln (Sperren/Freigaben für IP, Netz, E-Mail, Domain, Benutzername, Textteil – Freigaben haben Vorrang) und auf Inhaltsmerkmale: viele oder gekürzte Links, BBCode-Links, ungültige E-Mail-Adresse, gefülltes Honigtopf-Feld und Header-Einschleusung (Zeilenumbruch in Betreff, Name oder E-Mail-Adresse – damit lassen sich Mail-Formulare als Spam-Schleuder missbrauchen).

curl -s https://captcha.empedia.cloud/captcha/v1/check -H 'Content-Type: application/json' \\
  -d '{"sitekey":"ek_site_…","secret":"'"$EMPEDIA_CAPTCHA_SECRET"'","fields":{"ip":"203.0.113.9","email":"anna@example.org","message":"Hallo"}}'
# {"success":true,"verdict":"allow","risk":0,"reasons":[]}

Fertige Beispiele (PHP, Node.js, Python, curl) und die Verwaltung eigener Regeln finden Sie in der Oberfläche unter „Inhaltsprüfung“, „Regeln“ und „Beispiele“. Mit POST /captcha/v1/report (kind: spam oder ham = war echt) melden Sie Fälle zurück; das System lernt daraus E-Mail-Adresse und IP-Adresse als eigene Regel (90 Tage gültig). Die Eingaben der Prüfung werden nicht gespeichert; gezählt werden nur Ergebnisse je Tag. Der Formularschutz wird nicht zusätzlich berechnet.

Seitenschutz (Vorschaltprüfung)

Der Seitenschutz schaltet vor Ihre ganze Website (oder Teile davon) eine kurze, automatische Prüfung – ähnlich einer „Browser wird überprüft“-Seite. Echte Besucher sehen sie für einen Augenblick (ohne Klick, ohne Bilderrätsel) und werden danach zur gewünschten Seite zurückgeleitet; Bots ohne echten Browser kommen nicht durch. Aktivieren Sie ihn unter „Seitenschutz“ der Website und binden Sie das passende Modul ein (PHP, WordPress oder Node.js/Express; Dateien und Beispiele stehen dort).

  • Ablauf: Ihr Server leitet unbestätigte Besucher an die Prüfseite bei uns; nach bestandener Aufgabe kommt der Besucher mit einem einmaligen Token zurück, Ihr Server prüft ihn (wie bei Formularen) und setzt ein signiertes Cookie empedia_pass (technisch notwendig, HttpOnly, gültig 5 Minuten bis 24 Stunden – einstellbar).
  • Suchmaschinen: Googlebot, Bingbot und Applebot werden per Rückwärts-Abfrage des DNS erkannt und durchgelassen (abschaltbar). Pfade wie /robots.txt und /sitemap sowie weitere eigene Ausnahmen bleiben frei.
  • Nicht-HTML und Schnittstellen: Anfragen ohne Freigabe, die keine Seite abrufen (z. B. POST), werden mit 403 abgewiesen.
  • Ausfallsicher: Ist der Dienst nicht erreichbar, lässt das Modul Besucher durch, damit Ihre Website nicht stillsteht.
  • Abrechnung: Jeder Aufruf der Prüfseite zählt als Anfrage; solange das Cookie gilt, entstehen keine weiteren.

Beobachten-Modus

Zum Einführen: Unter „Einstellungen“ schalten Sie den Beobachten-Modus ein. Anfragen werden bewertet und gezählt („hätte blockiert“), aber nie abgelehnt – Ihre Besucher merken nichts. So sehen Sie in der Übersicht, was der Schutz tun würde, und passen die Strenge an, bevor Sie scharf schalten. Die Inhaltsprüfung liefert dann verdict: allow mit observed: true und dem eigentlichen Ergebnis in would_be.

Automatisierung: API, Webhooks, Alarme

  • API: Domains, Regeln, Statistik, Änderungsprotokoll und CSV-Export sind mit einem API-Zugang (Scopes captcha:read / captcha:write, Anleitung) nutzbar; POST /api/captcha/sites/bulk legt bis zu 100 Domains auf einmal an (z. B. für Agenturen). Alle Endpunkte stehen in der API-Referenz.
  • Webhooks: captcha.attack_detected (ungewöhnlich viele abgelehnte Anfragen), captcha.quota_80 und captcha.quota_100 (Anfragenkontingent) – siehe Webhooks.
  • Benachrichtigungen: bei einem Angriff und bei 80 % bzw. 100 % des Kontingents erhalten Inhaber und Administratoren eine Benachrichtigung (im System, per E-Mail, optional als Push).
  • KI-Assistenten (MCP): mit dem Scope captcha:read können Assistenten Domains und Kennzahlen lesen (list_captcha_domains, get_captcha_domain).
  • Änderungsprotokoll: unter „Einstellungen“ sehen Sie, wer wann was geändert hat – ohne IP-Adressen und ohne Werte.

Spam melden und gemeinsam lernen

Mit report (SDK) bzw. POST /captcha/v1/report melden Sie, dass eine Anfrage Spam war („spam“) oder doch echt („ham“). Der Dienst lernt daraus eine eigene Regel für Ihre Domain (90 Tage). Melden mindestens drei voneinander unabhängige Organisationen denselben Wert, wird er nach einer Prüfung durch uns zu einer gemeinsamen Sperre für alle Domains – eine Freigabe als „echt“ in Ihrer Domain schützt Sie immer vor einer gemeinsamen Sperre. Es werden keine Inhalte Ihrer Nachrichten weitergegeben, nur die gemeldete E-Mail- oder IP-Adresse.

Fertige Bausteine: SDKs und WordPress-Plugin EMPEDIA Shield

  • WordPress: das Plugin „EMPEDIA Shield“ enthält den Bot-Schutz (EMPEDIAcaptcha) als Modul und schützt Anmeldung, Registrierung, „Passwort vergessen“, Kommentare, Contact Form 7 und WooCommerce (Anmeldung, Registrierung, Kasse) und kann optional den Seitenschutz vor die ganze Website setzen (Verwaltung, Anmeldung, Cron und angemeldete Personen bleiben frei). Plugin als ZIP herunterladen. Mit „Bot-Schutz → Aktivieren“ werden Schlüssel für die Domain angelegt und eingetragen; wer sie von Hand pflegt, trägt sie im Reiter „Bot-Schutz“ ein; den geheimen Schlüssel besser in der wp-config.php als EMPEDIA_CAPTCHA_SECRET. Bei einem Ausfall des Dienstes lässt das Plugin Anfragen standardmäßig durch.
  • React / Next.js: das Paket @urbanstudio/empedia-captcha-react liefert eine fertige Komponente für den Client, die Prüfung läuft serverseitig weiter mit dem Node-SDK:
    import { EmpediaCaptcha } from '@urbanstudio/empedia-captcha-react';
    
    <EmpediaCaptcha sitekey="ek_site_…" action="contact" onToken={setToken} />
    sowie Erweiterungen für TYPO3 und Shopware 6 (Beta, noch nicht an einer echten Installation geprüft).
  • SDKs ohne Abhängigkeiten für PHP, Node.js und Python: verify (Token prüfen), check (Inhaltsprüfung), report (Spam melden) und Hilfen für das Widget. Das Secret kommt nur aus der Umgebung bzw. aus einer Konstante.
  • Viele Domains: mit scripts/ops/captcha-bulk-domains.mjs legen Agenturen aus einer CSV-Liste Domains per API an und erhalten eine Datei mit Website-Schlüsseln und Secrets (Secrets werden nur einmal geliefert).

Pakete installieren: composer require urbanstudio/empedia-captcha (Packagist), npm i @urbanstudio/empedia-captcha (npm) oder pip install empedia-captcha (PyPI). Für React gibt es @urbanstudio/empedia-captcha-react; die TYPO3- und Shopware-Pakete sind noch Beta.

Antwort der Prüfung

{"success": true, "hostname": "example.com", "action": "contact", "score": 92, "challenge_ts": "…"}
{"success": false, "error-codes": ["timeout-or-duplicate"]}
FehlercodeBedeutung
missing-input-secret / invalid-input-secretSecret fehlt oder gehört nicht zur Domain
missing-input-response / invalid-input-responseToken fehlt oder ist verändert
timeout-or-duplicateToken abgelaufen oder schon einmal geprüft
action-mismatchToken wurde für eine andere Aktion ausgestellt
score-too-lowVerhalten zu auffällig für die eingestellte Strenge

Antwortet der Dienst mit 503 service-disabled, hat der Betreiber ihn vorübergehend abgeschaltet (Notschalter); mit failOpen lassen die SDKs dann durch.

Ist das Kontingent einer Domain im Free-Paket erschöpft, bekommt das Widget keine Aufgabe mehr (429 quota-exceeded) und es entsteht kein Token. Mit failOpen fragen die SDKs dann ohne Token über GET /captcha/v1/status?sitekey=… (Antwort { "quota_exceeded": true|false }) nach und lassen die Anfrage durch (quota-exceeded in den Fehlercodes), damit keine Besucher ausgesperrt werden.

Gründe der Inhaltsprüfung (reasons) u. a.: honeypot, header_injection, ip_listed, ip_community, email_listed, email_community, email_disposable (Wegwerf-Adresse), email_no_mx (Domain kann keine E-Mail empfangen), duplicate_text (gleicher Text mehrfach in 10 Minuten), many_links, own_ip / own_email / own_domain / own_geo (Ihre Regeln).

Der Dienst ist nicht erreichbar? Entscheiden Sie in Ihrem Code bewusst, ob die Anfrage dann abgelehnt (sicherer) oder durchgelassen wird.

Testen

Mit dem Site-Key ek_test_site und dem Secret ek_test_secret besteht jede Prüfung (zählt nicht in der Statistik) – praktisch für die Entwicklung. Mit dem Site-Key ek_test_site_fail (gleiches Secret) fällt dagegen jede Prüfung durch – so testen Sie die Fehlerseite Ihres Formulars. Für lokale Tests auf localhost schalten Sie in den Einstellungen „localhost zulassen“ ein.

Wiederholungen, Eigene Adresse und Hinweis

  • Ohne Browser: Die SDKs (Node, PHP, Python, Go) beschaffen ein Token auch selbst (getToken/get_token): sie rechnen die Aufgabe und geben die Domain als Herkunft an. Das macht offene Endpunkte für Massenabfragen teuer, prüft aber keine Menschen.
  • Eigene Adresse (Whitelabel): Pakete mit Whitelabel liefern Widget und Schnittstelle unter der Adresse Ihrer verifizierten Agentur-Domain aus; die Beispiele in der Oberfläche verwenden sie automatisch. Nur diese Pakete dürfen den Hinweis „Geschützt durch EMPEDIAcaptcha“ mit data-badge="false" ausblenden.
  • Datenschutzerklärung: einen Textbaustein für Ihre Website finden Sie im öffentlichen Repository (docs/datenschutz-textbaustein.md) – bitte mit Ihrem Datenschutzbeauftragten abstimmen.

Pakete und Abrechnung

  • Gezählt werden Anfragen: jede ausgestellte Aufgabe (Bot-Prüfung, Seitenschutz) und jeder Aufruf der Inhaltsprüfung bei gültigem Schlüssel und erlaubtem Host – auch wenn die Prüfung später fehlschlägt, denn die Last entsteht beim Dienst. Aufrufe mit ungültigem Schlüssel oder fremdem Host zählen nicht. Bei Angriffen schützt Sie die Angriffserkennung (Benachrichtigung) und eine Obergrenze je Adresse und Aktion.
  • Im Free-Paket (1 Domain, 10.000 Anfragen im Monat) endet der Schutz mit dem Monatskontingent.
  • Einen Monat kostenlos testen: Starter, Pro und Business starten mit einer kostenlosen Testphase (einmal je Organisation). Zahlungsdaten geben Sie schon beim Start an; belastet wird erst nach der Testphase, und nur, wenn Sie nicht vorher kündigen (Einstellungen → Abonnement → „Abo verwalten“, Wirkung zum Ende der Testphase). Drei Tage vor dem Ende erinnern wir Sie per Benachrichtigung und E-Mail.
  • In bezahlten Stufen wird die Überschreitung je 1.000 Anfragen zum Monatsende über Ihr Guthaben abgerechnet (Guthaben & Kreditrahmen). Zusatzpakete erhöhen die Zahl der Domains.
  • Die Nutzung sehen Sie je Domain unter „Übersicht“.

Datenschutz

EMPEDIAcaptcha setzt in Formularen und Schnittstellen keine Cookies (nur der optionale Seitenschutz setzt auf Ihrer Website das technisch notwendige Cookie empedia_pass), nutzt weder localStorage noch sessionStorage und erstellt keinen Fingerabdruck. Die IP-Adresse des Besuchers wird nur kurzzeitig im Arbeitsspeicher für Begrenzungen und den Abgleich mit öffentlichen Sperrlisten genutzt und nicht gespeichert; in der Datenbank stehen nur Tageszähler je Website. Ob Sie das dennoch in Ihrer Datenschutzerklärung erwähnen, klären Sie mit Ihrer Datenschutzbeauftragten bzw. Ihrem Datenschutzbeauftragten (keine Rechtsberatung).