Dokumentation
CaptchaCore in 5 Minuten in dein Projekt integrieren.
1 Site & Keys erstellen
- Login unter
/admin - Unter Sites eine neue Site anlegen (Name + Domain)
- Unter API-Keys ein Key-Paar generieren
- Den
cc_pub_...(public) undcc_sec_...(secret) Key sicher speichern
2 Widget einbinden (Frontend)
Der public key (cc_pub_) wird im Browser verwendet.
<!-- In deinem HTML, vor </body> --> <script src="https://src-eu.captchacore.eu/widget/captchacore-v2.min.js" data-service-url="https://api.captchacore.eu" data-site-key="cc_pub_DEIN_KEY" async defer></script> <!-- Formular mit CaptchaCore --> <form data-captchacore="interactive" method="post"> <!-- Deine Formularfelder --> <div data-captchacore-widget></div> <button type="submit">Absenden</button> </form>
3 Token verifizieren (Backend)
Der secret key (cc_sec_) wird serverseitig verwendet.
POST https://api.captchacore.eu/api/v2/verify Header: X-CaptchaCore-Key: cc_sec_DEIN_SECRET Body: { "token": "<captchacore_token aus dem Formular>", "form_type": "register" } Response: { "valid": true, "decision": "allow", // allow | challenge | step_up | block "risk_score": 8, "confidence": 0.94, // 0.0–1.0 Signalabdeckung "reasons": ["pow_valid", "behavior_human_like", "ip_clean"], "step_up": null // Step-Up-Challenge falls noetig }
HTML Integration
Für statische Seiten, PHP-Projekte, Node.js oder jedes andere Backend.
Frontend
Das Widget wird automatisch an alle Formulare mit data-captchacore Attribut angeheftet. Es fügt ein verstecktes captchacore_token Input-Feld ein.
Backend (beliebige Sprache)
# curl Beispiel curl -X POST https://api.captchacore.eu/api/v2/verify \ -H "X-CaptchaCore-Key: cc_sec_DEIN_SECRET" \ -H "Content-Type: application/json" \ -d '{"token":"TOKEN_AUS_FORMULAR","form_type":"contact"}' # Antwort prüfen: valid=true UND action != "block"
Laravel Integration
1. Repository eintragen
Füge das CaptchaCore-Repository in deine composer.json ein:
{
"repositories": [
{
"type": "composer",
"url": "https://captchacore.eu/packages"
}
]
}
2. Paket installieren
composer require captchacore/laravel
3. .env konfigurieren
CAPTCHACORE_URL=https://captchacore.eu CAPTCHACORE_SITE_KEY=cc_pub_dein_key CAPTCHACORE_SECRET_KEY=cc_sec_dein_secret CAPTCHACORE_WIDGET_MODE=interactive # interactive | visible | invisible CAPTCHACORE_WIDGET_THEME=auto # auto | light | dark CAPTCHACORE_WIDGET_COLOR=#4ade80 CAPTCHACORE_WIDGET_LABEL=Ich bin kein Bot CAPTCHACORE_WIDGET_BRAND=CaptchaCore
Blade-Component
<form method="post" data-captchacore="interactive"> @csrf <!-- Formularfelder --> <x-captchacore::widget /> <button type="submit">Absenden</button> </form>
Middleware
// Route schützen Route::post('/register', RegisterController::class) ->middleware('captchacore:register'); // Oder als Validation Rule 'captchacore_token' => ['required', new CaptchaCoreToken('contact')] // Tests: fake() mockt alle Verifikationen CaptchaCore::fake();
Symfony Bundle
Für Symfony 6.4 LTS und 7.x. Vier Integrationswege: FormType, Validator-Constraint, Controller-Attribute und Security-Badge.
1. Installieren
composer require captchacore/captchacore-bundle
Symfony Flex registriert das Bundle und legt config/packages/captchacore.yaml automatisch an.
2. .env konfigurieren
CAPTCHACORE_URL=https://api.captchacore.eu CAPTCHACORE_SITE_KEY=cc_pub_xxxxxxxxxxxxxxxxxxxxxxxxxxxx CAPTCHACORE_SECRET_KEY=cc_sec_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
FormType (empfohlen)
use CaptchaCore\SymfonyBundle\Form\Type\CaptchaCoreType; $builder ->add('email', EmailType::class) ->add('message', TextareaType::class) ->add('captcha', CaptchaCoreType::class, [ 'form_type' => 'contact', ]);
Controller-Attribute
use CaptchaCore\SymfonyBundle\Security\Attribute\RequiresCaptcha; #[Route('/contact', methods: ['POST'])] #[RequiresCaptcha(formType: 'contact')] public function submit(Request $request): Response { /* ... */ }
Validator-Constraint (DTOs)
use CaptchaCore\SymfonyBundle\Validator\CaptchaCoreToken; final class ContactDto { public function __construct( #[Assert\NotBlank] public string $email, #[CaptchaCoreToken(formType: 'contact')] public string $captchaToken, ) {} }
Programmatisch
use CaptchaCore\SymfonyBundle\Client\CaptchaCoreClient; $result = $this->captcha->verify($token, 'login'); if ($result->blocked()) { throw new AccessDeniedHttpException(); } // Properties: valid, riskScore, action, confidence, reasons, stepUp
Twig (standalone)
{{ captchacore_widget(mode: 'interactive') }}
Tests
CaptchaCoreClient::fake(VerificationResult::allow()); $this->client->request('POST', '/contact', [...]); self::assertResponseIsSuccessful();
WordPress Plugin
- Plugin installieren — ZIP hochladen oder Ordner nach
wp-content/plugins/kopieren - Aktivieren unter Plugins
- Einstellungen > CaptchaCore öffnen
- Service-URL, Site Key und Secret Key eintragen
- Widget-Modus, Theme und Farbe wählen
- Gewünschte Formulare aktivieren (Login, Register, Kommentare, etc.)
Kein Code nötig. Das Plugin bindet das Widget automatisch in alle aktivierten WordPress-Formulare ein und verifiziert Tokens serverseitig.
API Referenz
GET /api/v2/challenge
PoW-Challenge anfordern. Auth: X-CaptchaCore-Key: cc_pub_...
Response: { "nonce": "a3f8...", "difficulty": 4, "algorithm": "sha256", "expires_at": 1712345678 }
POST /api/v2/verify
Token verifizieren. Auth: X-CaptchaCore-Key: cc_sec_...
Body: { "token": "...", "form_type": "register" } Response: { "valid": true, "risk_score": 8, "action": "allow" }
Antwort immer HTTP 200. Prüfe valid und action.
GET /api/v2/status
Health-Check + Under-Attack-Status. Auth: cc_sec_...
Response: { "status": "ok", "under_attack": false, "version": "1.0.0" }
Widget Optionen
Das Widget wird über data- Attribute auf dem Container konfiguriert:
| Attribut | Werte | Standard | Beschreibung |
|---|---|---|---|
| data-theme | auto | light | dark | auto | Farbschema |
| data-color | Hex-Farbe | #34d399 | Akzentfarbe für Checkbox und Rahmen |
| data-label | Text | Ich bin kein Bot | Checkbox-Beschriftung |
| data-brand | Text oder leer | CaptchaCore | Branding rechts, leer = versteckt |
| data-size | normal | compact | normal | Widget-Grösse |
Widget Modi
Der Modus wird über data-captchacore="..." auf dem <form> gesetzt.
interactive
Empfohlen Widget immer sichtbar. PoW löst automatisch. Checkbox setzt sich selbst wenn genug menschliche Interaktion erkannt wird (3+ Zeichen getippt, Mausbewegung, 2+ Sekunden). Kein Klick nötig für echte User. Fallback: manueller Klick.
visible
Widget sichtbar. User muss die Checkbox klicken um die Verifikation zu starten. Ähnlich wie reCAPTCHA v2.
invisible
Kein sichtbares UI. PoW löst komplett im Hintergrund. Token wird automatisch beim Submit eingefügt. Ideal wenn kein visueller Schutz gewünscht ist.
Adaptive Risk Engine
Der Risk-Score ist die gewichtete Summe aller Penalties (0-100). Die Schwellwerte werden durch das aktive Site-Profil und die Form-Policy bestimmt. Die V2 Response enthält zusätzlich einen Confidence-Score (0.0-1.0) und maschinenlesbare Reason-Codes.
| Score | Aktion | Bedeutung |
|---|---|---|
| 0-29 | allow | Menschlich, durchlassen |
| 30-59 | challenge | Verdacht, wird durchgelassen aber geloggt |
| 60-100 | block | Bot erkannt, blockieren |
Penalty-Faktoren
pow_failed: +100 PoW falsch oder fehlend nonce_reused: +100 Replay-Angriff ip_blocked: +100 IP auf Blockliste rate_limit_hit: +80 Zu viele Requests user_agent_headless: +70 Puppeteer/Playwright tor_exit: +60 TOR Exit Node behavior_bot: +50 Verhalten bot-typisch time_too_fast: +35 Submit < 1.5 Sekunden asn_hosting: +25 Rechenzentrum-ASN behavior_suspicious: +20 Verhalten verdächtig
V2.1 Advanced Bot Detection
Zusätzliche Signale die selbst getarnte Headless-Browser entlarven. Alle Prüfungen sind kontextsensitiv: Mobile Geräte und Privacy-Browser (Safari/Firefox) werden korrekt als legitim erkannt und nicht falsch geflaggt.
env_automation_globals: +90 Selenium/Puppeteer/CDP Leak im window-Objekt env_ua_brand_bot: +80 UA Client Hints verraten Automation-Framework env_software_renderer: +50 WebGL nutzt SwiftShader/llvmpipe = headless env_canvas_too_fast: +40 Canvas-Render < 2ms = headless (Mensch: 5-50ms) env_no_storage: +30 localStorage UND indexedDB fehlen env_raf_robotic: +25 requestAnimationFrame perfekt uniform (CV < 0.05) env_no_webgl_ext: +25 0 WebGL-Extensions auf Desktop = headless header_no_sec_fetch: +25 Sec-Fetch-* Header fehlen = altes/scripted Client header_no_accept_lang: +20 Accept-Language fehlt = scripted env_no_hover: +5 Hover nicht unterstützt (selten valide auf Desktop) env_audio_hash_missing: +5 OfflineAudioContext blockiert (Privacy-Browser ok)
V2.1 erhöht die Erkennungsrate von Stealth-Frameworks (Playwright Stealth, Puppeteer Stealth) deutlich, ohne legitime Nutzer zu beeinträchtigen.
Site-Profile & Form-Policies
Die V2 Risk Engine bewertet kontextabhängig: Login-Formulare werden strenger bewertet als Kontaktformulare. Site-Profile definieren die Grundhaltung, Form-Policies überschreiben gezielt pro Formular-Typ.
Site-Profile (Presets)
Jede Site wird einem Profil zugeordnet. Das Profil bestimmt Schwellen, Challenge-Typen und Behavioral-Gewichtungen.
| Profil | Allow < | Challenge < | Difficulty | Einsatz |
|---|---|---|---|---|
| Low Friction | 40 | 70 | 2 | Newsletter, Kommentare, Info-Seiten |
| Balanced | 30 | 60 | 4 | Standard für die meisten Formulare |
| Auth Hardened | 20 | 50 | 5 | Login, Registrierung, Passwort-Reset |
| High Security | 15 | 40 | 6 | Checkout, Admin-Aktionen, Bezahlung |
Form-Policies
Form-Policies überschreiben das Site-Profil für bestimmte Formular-Typen. Der form_type wird beim Verify-Request mitgeschickt.
| form_type | Profil | Allow < | Challenge < | Fail-Mode |
|---|---|---|---|---|
| login | Auth Hardened | 20 | 50 | fail_closed |
| register | Auth Hardened | 20 | 50 | fail_closed |
| password_reset | High Security | 15 | 40 | fail_closed |
| checkout | High Security | 15 | 40 | fail_closed |
| contact | Balanced | 30 | 60 | fail_open |
| comment | Low Friction | 35 | 65 | fail_open |
| newsletter | Low Friction | 40 | 70 | fail_open |
Merge-Reihenfolge
Spätere Ebenen überschreiben frühere:
1. Globale Defaults (config: allow<30, challenge<60) 2. Site-Profil (z.B. "Auth Hardened" → allow<20, challenge<50) 3. Form-Policy (z.B. login → allow<15, fail_closed)
Integration (Entwickler)
Der form_type wird beim Widget-Einbau und beim Verify-Request angegeben:
<!-- Widget: form_type als data-Attribut --> <form data-captchacore="interactive" data-form-type="login"> <div data-captchacore-widget data-form-type="login"></div> </form> // Verify-Request: form_type im Body POST /api/v2/verify { "token": "...", "form_type": "login" // Steuert welche Policy angewendet wird }
Verfügbare Typen: login, register, contact, comment, checkout, password_reset, newsletter, custom. Ohne form_type werden die globalen Defaults verwendet.
Fehlerbehandlung & Fail-Open
Wenn der CaptchaCore-Service nicht erreichbar ist, kann das Verhalten konfiguriert werden:
Fail-Open (Standard)
Formulare werden trotzdem durchgelassen. Verfügbarkeit > Sicherheit bei Ausfall. Empfohlen für die meisten Sites.
CAPTCHACORE_FAIL_OPEN=true
Fail-Closed
Formulare werden blockiert wenn der Service nicht antwortet. Nur für hochkritische Systeme.
CAPTCHACORE_FAIL_OPEN=false
Alle API-Calls haben einen Timeout von 3 Sekunden. Bei Timeout greift die Fail-Open/Closed-Konfiguration.
Keys & Rotation
Jede Site hat ein Key-Paar: Site Key (public, im Browser) und Secret Key (geheim, nur Server).
Key-Formate
cc_pub_6e65b5c4597a688c93f3be6e345ee1a5... ← 7 + 64 hex = 71 Zeichen cc_sec_8bb043aa6424a1fdb3e048d2d3232894... ← 7 + 64 hex = 71 Zeichen
Key-Rotation
Bei Rotation wird der alte Key in den Status rotated versetzt und bleibt noch 24 Stunden gültig. So können Rolling Deployments ohne Downtime durchgeführt werden.
Secret Key Sicherheit
- Secret Key wird als SHA-256 Hash in der Datenbank gespeichert
- Klartext wird nur einmalig nach Erstellung angezeigt
- Kann nicht wiederhergestellt werden — bei Verlust: neuen Key generieren
- Wird niemals in Logs, API-Responses oder Fehlermeldungen ausgegeben
Under-Attack-Mode
Bei einem Angriff (hohe Block-Rate) kann der Schutz verstärkt werden:
Automatische Aktivierung
Wenn über 70% aller Requests in einem 5-Minuten-Fenster blockiert werden, aktiviert sich der UAM automatisch.
# Konfigurierbar in den globalen Einstellungen uam.auto_threshold: 0.70 # 70% Block-Rate uam.window_minutes: 5 uam.auto_deactivate_after: 3600 # 1 Stunde uam.cookie_ttl_minutes: 30
Im UAM erhöht sich die PoW-Schwierigkeit um +1 Stufe. Verifizierte Besucher erhalten ein HMAC-signiertes Access-Cookie (HttpOnly, SameSite=Strict).
Backend-Beispiele
Der Verify-Endpoint kann von jedem Backend aufgerufen werden. Hier Beispiele für gängige Sprachen:
PHP (ohne Framework)
$token = $_POST['captchacore_token'] ?? ''; $ch = curl_init('https://api.captchacore.eu/api/v2/verify'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 3, CURLOPT_HTTPHEADER => [ 'X-CaptchaCore-Key: cc_sec_DEIN_SECRET', 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => json_encode([ 'token' => $token, 'form_type' => 'contact', ]), ]); $result = json_decode(curl_exec($ch), true); if (!$result['valid']) { die('Bot erkannt.'); }
Node.js
const token = req.body.captchacore_token; const res = await fetch('https://api.captchacore.eu/api/v2/verify', { method: 'POST', headers: { 'X-CaptchaCore-Key': process.env.CAPTCHACORE_SECRET_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ token, form_type: 'register' }), }); const { valid, risk_score, action } = await res.json(); if (!valid) return res.status(403).json({ error: 'Bot detected' });
Python
import requests result = requests.post( 'https://api.captchacore.eu/api/v2/verify', headers={'X-CaptchaCore-Key': 'cc_sec_DEIN_SECRET'}, json={'token': token, 'form_type': 'login'}, timeout=3, ).json() if not result['valid']: raise Exception('CaptchaCore verification failed')
Troubleshooting
Widget lädt nicht / 500 auf /api/v2/challenge
Domain prüfen: Ist die Domain in den Site-Einstellungen unter "Erlaubte Domains" eingetragen? Wildcards möglich: *.example.com
CORS-Fehler im Browser
Der CaptchaCore-Service muss die anfragende Domain kennen. Domain in den Site-Einstellungen hinzufügen. Widget-JS und Worker-JS werden mit Access-Control-Allow-Origin: * ausgeliefert.
Token ist null / leer
Das Widget-Script muss vor dem Formular-Submit geladen sein. Prüfe: Ist data-captchacore auf dem <form>? Ist data-captchacore-widget Container vorhanden (für visible/interactive)?
PoW FAIL / Nonce FAIL
Der Nonce ist 5 Minuten gültig und einmalig verwendbar. Wenn der User zu lange wartet oder doppelt absendet, schlägt die Verifikation fehl. Seite neu laden.
Checkbox-Haken nicht sichtbar
Externe CSS-Frameworks können das SVG überschreiben. Das Widget nutzt !important für alle kritischen Styles. Bei Problemen: Browser-DevTools > Elements > Computed Styles prüfen.
Risk Score zu hoch für echte User
Behavioral-Schwellwerte prüfen: time_to_submit_ms unter 1500ms = +35 Penalty. User muss genug Zeit auf der Seite verbringen und interagieren.
Infrastruktur & Domains
Domain-Architektur
| Domain | Zweck | Typ |
|---|---|---|
| api.captchacore.eu | Challenge, Verify, Status, Version | API (JSON) |
| src-eu.captchacore.eu | Widget JS + Worker (EU-only CDN) | CDN (Standard) |
| src.captchacore.eu | Widget JS + Worker (Globales CDN) | CDN (optional) |
| captchacore.eu | Website, Admin-Panel, Docs | Frontend |
Content Security Policy (CSP)
Wenn Sie auf Ihrer Website eine Content Security Policy verwenden, müssen folgende Domains erlaubt werden:
# Minimal (EU-only CDN + API) script-src https://src-eu.captchacore.eu; connect-src https://api.captchacore.eu https://src-eu.captchacore.eu; worker-src blob:; # Mit globalem CDN (zusätzlich) script-src https://src.captchacore.eu; connect-src https://src.captchacore.eu;
Warum diese Einträge?
- script-src — Das Widget-JS (
captchacore-v2.min.js) wird vom CDN geladen - connect-src (API) — Das Widget ruft
/api/v2/challengeper fetch() auf - connect-src (CDN) — Der PoW-Worker wird per fetch() vom CDN nachgeladen
- worker-src blob: — Der Worker wird als Blob-URL instanziiert (vermeidet CORS)
CORS-Header
CaptchaCore setzt automatisch die richtigen CORS-Header auf allen API-Endpoints. Sie müssen auf Ihrer Seite keine CORS-Konfiguration vornehmen. Die API antwortet mit:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: Content-Type, Accept, X-CaptchaCore-Key
NGINX-Beispiel für Ihre Webseite
Falls Sie eine strenge CSP auf Ihrer Webseite konfiguriert haben:
# NGINX — CSP für CaptchaCore Widget add_header Content-Security-Policy "script-src 'self' https://src-eu.captchacore.eu; connect-src 'self' https://api.captchacore.eu https://src-eu.captchacore.eu; worker-src 'self' blob:;"
Datenschutz (DSGVO)
Was gespeichert wird
- IP-Hash (täglicher Salt)
- Anonymisierte IP (letztes Oktett 0)
- Ländercode (2 Buchstaben)
- User-Agent-Hash
- Risk-Score + Ergebnis
- Automatische Löschung (Standard: 30 Tage)
Was NICHT gespeichert wird
- Keine IP-Klartexte
- Keine Cookies (außer UAM)
- Keine Maus-Trajektorien
- Keine Tastatureingaben
- Keine Formulardaten
- Keine externen Requests