Ein Token prüfen
Ihr Server empfängt das Formular mit dem Feld antisy-token, das das Script ausgefüllt hat, und lässt das Token mit einem einzigen Aufruf prüfen. Die Antwort sagt, ob der Besucher angenommen ist.
Die Anfrage
POST https://api.antisy.com/v1/siteverify, mit einem Body application/x-www-form-urlencoded oder application/json.
- secret
- Pflicht. Ihr Verifizierungs-Secret (64 alphanumerische Zeichen), im Body und nirgends sonst.
- response
Das Token, so wie es im Feld
antisy-token(vom Script ausgefüllt) oder im Headerx-antisy-token(von Ihrer Seite gesetzt) angekommen ist. Eine Zeichenkette mit 1 bis 2048 druckbaren ASCII-Zeichen. Leer oder fehlend wird es als fehlendes Token gelesen.Prüfen Sie es bei sich vor dem Aufruf. Ausserhalb dieser Form behandelt die API es als gefälschtes Token: 200,
successgleichfalse,verdictgleichdeny,invalid-input-response.- idempotency_key
- Optional. Eine UUID; jeder andere Wert wird abgelehnt. Siehe weiter unten.
- remoteip
- Senden Sie es nicht. Es wird ignoriert, welcher Wert auch immer, und nie abgelehnt: Entfernen Sie es.
- Senden Sie keinen Header
Authorization. Seine Anwesenheit schaltet die Anfrage in einen anderen Modus, den des SDK, in dem das Secret kein gültiger Nachweis ist: Antwort401, in einem Body anderer Form. Ein Secret, das alsAuthorization: Bearergesendet wird, wird ebenso abgelehnt. - Rufen Sie die Route von Ihrem Server auf, nie aus einem Browser: Sie sendet keinen CORS-Header, ein Browser kann die Antwort nicht lesen.
Die Antwort
{
"success": true,
"verdict": "allow",
"flags": [],
"error-codes": [],
"challenge_ts": "2026-09-24T10:00:00Z",
"hostname": "shop.example",
"action": "contact",
"event_id": "evt_01J7X4M2Q9K8ZP3R5T6V7W8Y9A"
}- success
truegenau dann, wenn der Besucher angenommen ist. Das ist das Feld, das Sie lesen, wenn Sie nur einen Boolean wollen.- verdict
allowoderdeny, und nichts anderes.successist genau danntrue, wennverdictallowist: Beide sagen dasselbe.- flags
- Die Liste der Zustände, die keine Fehler sind. Sie ist offen: Ignorieren Sie die, die Sie nicht kennen (siehe weiter unten).
- error-codes
- Die Liste der Fehlercodes, leer, wenn nichts falsch ist (siehe weiter unten).
- challenge_ts
- Die Zeit der Hinterlegung des Tokens, im Format ISO 8601 in UTC, bei einem
allow, hinter dem eine Hinterlegung steht. Einallowohne Hinterlegung trägtnull, zum Beispiel: Erfassung aus und Token fehlt, Website oder Organisation gesperrt, Test-Token, Hinterlegung, die unsere Datenbank nicht schreiben konnte (mitinternal-error). Machen Sie es also nicht zur Bedingung, um einen Besucher anzunehmen.nullauch bei jeder Ablehnung, was immer ihre Ursache ist. - hostname
- Bei einem
allowder Hostname der Seite, die das Token angefordert hat, wenn ihre Origin bestätigt ist.nullsonst, und bei jeder Ablehnung. - action
- Bei einem
allowdie Bezeichnung, die antoken()übergeben oder perdata-antisy-actionauf das Formular gesetzt wurde, odernull, wenn es keine gab.nullauch bei jeder Ablehnung. - event_id
- Die Kennung dieser Prüfung, in der Form
evt_gefolgt von 26 Zeichen. Nennen Sie sie, wenn Sie dem Support (support@antisy.com) zu einem Fall schreiben.
Die Antwort enthält weder Score noch Schwelle noch Grund, in keinem Modus: ein Ergebnis, nie die Einzelheit, die es hervorgebracht hat. Jeder genannte Grund würde dem, der den Schutz umgehen will, verraten, was ihn aufgehalten hat, und die Gründe bleiben bei Antisy. Die Fehlercodes sagen, was Ihre Einbindung korrigieren muss, nicht was die Erkennung gesehen hat. Ein Köder und eine Übermittlung, die wegen dessen abgelehnt wird, was ihre Herstellung beweist, erhalten dieselbe Antwort wie jede Ablehnung. Sie trägt Cache-Control: no-store und den Header X-Antisy-Api-Version: 1.
Die Kennzeichen
test_key- Die Prüfung wurde mit einem Test-Secret gemacht.
over_quota- Das monatliche Kontingent der Stufe Kostenlos ist überschritten: Der Score entscheidet die Antwort nicht mehr, aber die Tür bleibt (ein fehlendes Token, solange die Erfassung der Website eingeschaltet ist, wird abgelehnt, wie ein ungültiges, gefälschtes, wiederholtes, abgelaufenes, zu einer anderen Website gehörendes oder nicht rechtzeitig berechnetes Token, und ebenso ein Besucher Ihrer Sperrliste). Ein Zustand Ihres Kontos, zu protokollieren.
degraded- Eine Quelle von Antisy war für diese Prüfung nicht verfügbar: Die Antwort wird ohne sie gegeben. Protokollieren Sie das (siehe internal-error).
idempotent_replay- Wiederholte Antwort: derselbe idempotency_key innerhalb von 60 Sekunden.
Felder, Kennzeichen und Codes können hinzukommen, ohne dass sich die Version ändert. Ein Bruch der Kompatibilität würde eine Route /v2/ schaffen: Lesen Sie, was Sie kennen, und ignorieren Sie den Rest.
Was mit jedem Ergebnis tun
allowsuccessgleichtrue. Veröffentlichen oder speichern Sie die Nachricht.denysuccessgleichfalse. Der Besucher kommt nicht durch: allgemeine Ablehnung, ohne den Grund zu verraten. Der Besucher erfährt nichts von dem, was geschehen ist; nur Ihr Server weiss es.
Es gibt nur diese zwei Ausgänge. Wollen Sie eine Moderation oder eine Bestätigung per E-Mail, entscheiden Sie das selbst, anhand Ihrer eigenen Signale. Wie streng Antisy ablehnt, ist eine Einstellung Ihrer Website im Dashboard: Strict, Équilibré (Standard) oder Permissif, beschrieben im Schnellstart.
Dieser Aufruf eignet sich für Formulare mit geringem Risiko. Er bindet das Token nicht an ein Konto: Verwenden Sie ihn nicht für ein Login oder eine Registrierung. Das Node-SDK (Express, Fastify, Next.js) wird mit seiner Dokumentation auf npm veröffentlicht werden; es ist noch nicht veröffentlicht.
Was nie durchkommt
Unabhängig vom Prüfmodus Ihrer Website werden diese Fälle abgelehnt: success gleich false, verdict gleich deny.
- Ein fehlendes Token, auf einer Website, deren Erfassung im Browser eingeschaltet ist (
missing-input-response). Auf einer Website mit ausgeschalteter Erfassung wird das Fehlen nicht angelastet: Eine neue Website beginnt mit ausgeschalteter Erfassung. - Ein erfundenes, unlesbares Token, eines mit einer Form ausserhalb der Grenzen, oder eines, das für eine andere Ihrer Websites ausgegeben wurde (
invalid-input-response). - Ein schon geprüftes oder abgelaufenes Token, auch nur um wenige Sekunden (
timeout-or-duplicate). - Eine Übermittlung, deren Herstellung bewiesen ist: Ein Programm hat sie hergestellt, nicht der Browser. Die Antwort trägt keinen Fehlercode und sagt nicht, was sie verraten hat.
- Ein Token, dessen Berechnung im Hintergrund nicht rechtzeitig fertig wurde (sehr langsames Gerät, verstecktes Tab, zu kurze Frist
totalTimeoutMs): Es geht ohne seine Lösung. Das ist kein Beweis der Herstellung, aber es wird ebenso abgelehnt, ohne Fehlercode; ein neuer Versuch macht die Berechnung mit einem frischen Token neu (die Frist der Berechnung). - Ein fehlendes oder ungültiges Token wird nicht von einer Zulassungsliste aufgefangen, wenn Antisy eine für Ihre Website gesetzt hat, auf Ihren schriftlichen Wunsch an den Support: Sie befreit von der Bewertung, nicht vom Token.
Diese Regel gilt auch über das monatliche Kontingent der Stufe Kostenlos hinaus. Der Score entscheidet dann nicht mehr über die Antwort: Eine Übermittlung, die nichts von diesen Fällen hat, kommt durch, mit dem Kennzeichen over_quota. Aber die Tür bleibt geschlossen: Ein fehlendes (Erfassung an), ungültiges, gefälschtes, wiederholtes, abgelaufenes oder zu einer anderen Website gehörendes Token, oder eines, dessen Berechnung nicht rechtzeitig fertig wurde, erhält success gleich false wie unter dem Kontingent, mit denselben Fehlercodes und over_quota in flags. Das Kennzeichen ändert also nichts an Ihrem Code: Es ist ein Zustand Ihres Kontos, zu protokollieren. Ihre Übermittlungen ohne Token oder mit einem falschen Token zählen, wie bisher, im Kontingent. Eine Sperrliste, die Antisy für Ihre Website auf Ihren schriftlichen Wunsch an den Support gesetzt hat (das Dashboard verwaltet diese Listen nicht), gilt ebenfalls: Ein gesperrter Besucher erhält success gleich false ausserhalb des Kontingents, mit oder ohne Token; eine Zulassungsliste dagegen befreit nicht vom Token.
Gültigkeitsdauer und einmalige Verwendung
- Ein Token ist 60 Sekunden nach seiner Hinterlegung gültig. Nach dieser Frist gibt die Prüfung
successgleichfalseundtimeout-or-duplicatezurück, was auch immer sonst gilt. - Es lässt sich nur einmal prüfen. Ein zweiter Aufruf mit demselben Token ergibt
timeout-or-duplicate.
Einen Aufruf wiederholen: idempotency_key
Ist Ihr Aufruf vielleicht durchgegangen, Sie haben aber die Antwort nicht gelesen (Unterbruch, Zeitlimit), ergäbe ein erneutes Senden ohne Vorkehrung timeout-or-duplicate. Senden Sie einen idempotency_key (eine UUID): Ein neuer Aufruf mit demselben Schlüssel innerhalb von 60 Sekunden wiederholt dasselbe Ergebnis und dieselbe event_id, mit dem Kennzeichen idempotent_replay, ohne das Token erneut zu prüfen. Die Fehlercodes der ersten Antwort werden nicht übernommen: error-codes ist leer, und flags trägt nur idempotent_replay, dazu over_quota, wenn die erste Antwort es trug. Diese Wiederholung setzt voraus, dass die erste Antwort aufbewahrt wurde: Das ist nie der Fall mit einem Test-Secret, noch wenn der erste Aufruf gescheitert ist, bevor sie aufbewahrt wurde. Das Token wird dann neu bewertet, ohne neu gezählt zu werden: eine neue event_id, ohne idempotent_replay, und ein Ergebnis, das vom ersten abweichen kann.
Ihr Server erzeugt den Schlüssel: eine neue UUID pro Übermittlung, nur wiederverwendet, um diesen Aufruf zu wiederholen. Lesen Sie ihn nie aus einem Feld des Formulars, einem Header oder der Anfrage des Besuchers: Ein Schlüssel, den der Besucher wählt, würde ihm erlauben, die Antwort einer schon angenommenen Übermittlung zu wiederholen und mit demselben Token während 60 Sekunden erneut durchzukommen.
# Ein Schlüssel pro Token: einmal erzeugt, dann bei jedem neuen Versuch unverändert wiederverwendet.
KEY=$(uuidgen)
for tentative in 1 2 3; do
printf 'secret=%s' "$ANTISY_SECRET" | curl -sS --max-time 3 https://api.antisy.com/v1/siteverify \
-d @- \
--data-urlencode response="$ANTISY_TOKEN" \
-d idempotency_key="$KEY" && break
sleep 1
doneFehlercodes
Die ersten fünf Codes begleiten eine Antwort 200, die ein Ergebnis trägt. Ein fehlendes oder abgelehntes Secret ist also kein HTTP-Fehler: Es ist eine Ablehnung (deny), damit die Route nicht zum Testen von Secrets dient und ein Konfigurationsfehler schon beim ersten Versuch sichtbar wird, ohne Ihre Website offen zu lassen. Die letzten drei sind Fehlerstatus, in einem Body ohne Ergebnis:
{ "success": false, "error-codes": ["rate-limited"] }missing-input-secretStatus 200Das Feld secret fehlt im Body der Anfrage. Das ist kein HTTP-Fehler: Die Antwort ist eine Ablehnung (success gleich false, Ergebnis deny), damit ein Konfigurationsfehler schon beim ersten Versuch sichtbar wird.
Korrigieren Sie den Aufruf. Solange er falsch ist, wird jeder Besucher abgelehnt: Protokollieren Sie ihn als Fehler.
invalid-input-secretStatus 200Das Secret ist unbekannt, widerrufen, fehlerhaft oder von einer anderen Art (ein Bewertungsschlüssel ist kein Verifizierungs-Secret), oder die Website ist geschlossen. Dieselbe Antwort wie bei einem fehlenden Secret: Die Route sagt nie mehr.
Prüfen Sie den Schlüssel im Tab « Clés » (Schlüssel) der Website. Dieselbe Wirkung wie beim vorherigen: Jeder Besucher wird abgelehnt.
missing-input-responseStatus 200Das Feld response ist leer, auf einer Website, deren Erfassung im Browser eingeschaltet ist. Der Besucher wird abgelehnt, unabhängig vom Prüfmodus der Website.
Das Script ist nicht gelaufen, oder das Formular ist vom Script nicht abgedeckt und die Seite hat token() nicht aufgerufen. Siehe die Seite zum Browser-Script.
invalid-input-responseStatus 200Das Token ist für diese Website nicht gültig: erfunden, verändert, für eine andere Ihrer Websites ausgegeben, oder von einer Form ausserhalb der Grenzen (mehr als 2’048 Zeichen, nicht druckbare Zeichen). Der Besucher wird abgelehnt.
Prüfen Sie, dass Sie das Token so weitergeben, wie es angekommen ist, ohne es zu kürzen, und dass es wirklich von der Seite dieser Website stammt.
timeout-or-duplicateStatus 200Das Token wurde schon geprüft, oder es ist älter als 60 Sekunden. Der Besucher wird abgelehnt.
Prüfen Sie ein Token nur einmal. Um einen Aufruf nach einem Unterbruch zu wiederholen, senden Sie idempotency_key. Sonst lassen Sie das Formular erneut senden: Der Browser erzeugt ein neues Token.
bad-requestStatus 400, 405, 415Von Ihrem Aufruf fehlerhaft gebildete Anfrage: unlesbarer Body, nicht akzeptierter Content-Type oder Zeichensatz, komprimierter Body, unbekanntes Feld, idempotency_key, der keine UUID ist, andere Methode als POST. Der Body trägt kein Ergebnis.
Der Fehler liegt in Ihrem Aufruf. Protokollieren Sie ihn als Fehler. Die Übermittlung wurde nicht geprüft: Lassen Sie sie nicht durch, lehnen Sie sie ab.
rate-limitedStatus 429Zu viele Aufrufe auf diesem Weg. Der Header Retry-After gibt die Wartezeit an, in Sekunden. Ein Angreifer kann diesen Status durch Masse auslösen.
Standardmässig lassen Sie durch und protokollieren. Für ein sensibles Formular lehnen Sie ab: siehe « Wenn die API nicht antwortet ».
internal-errorStatus 500, 503Ausfall bei Antisy, zum Beispiel eine nicht verfügbare Datenbank. Der Code kann auch ein allow begleiten: Bei Antisy konnte dieses Token nicht gespeichert werden.
Lassen Sie die Übermittlung durch und protokollieren Sie sie.
Eine andere Methode als POST erhält 405, im oben gezeigten Fehler-Body, mit bad-request.
Eine gesperrte Website oder Organisation: Ihr Secret antwortet dann success gleich true und verdict gleich allow, ohne Kennzeichen und ohne Fehlercode, ausser test_key bei einem Test-Secret. Eine Sperrung des Kontos macht Ihre Formulare nicht kaputt, aber in dieser Zeit wird nichts geprüft. Eine geschlossene Website dagegen wird wie ein unbekanntes Secret abgelehnt (invalid-input-secret).
Wenn die API nicht antwortet
Regel: Lassen Sie nur durch, wenn Antisy nicht antwortet
Schreiben Sie « wenn success falsch ist, ablehnen », blockieren Sie während eines Ausfalls von Antisy alle Ihre Formulare. Ein Ausfall bei uns darf Sie nicht Ihre Besucher kosten. Aber « durchlassen » gilt nur für ein echtes Ausbleiben der Antwort: Ein Bot, der einen Fehler auslöst, darf daraus keinen Freipass ziehen.
- Prüfen Sie das Token vor dem Aufruf. Ein vorhandenes Token ist eine Zeichenkette mit 1 bis 2048 druckbaren ASCII-Zeichen. Sonst rufen Sie Antisy nicht auf: Die Übermittlung ist nicht geprüft, lehnen Sie sie ab. Ein leeres Token dagegen geht, wie es ist: Antisy weiss, ob die Website ein Token erwartet.
- Lassen Sie nur durch, und protokollieren Sie, bei einem Netzfehler, einem DNS-Fehler, einem überschrittenen Zeitlimit (3 Sekunden ist das Zeitlimit, das wir empfehlen) oder einer Antwort
5xx. - Lassen Sie nie durch bei
400,401,413,415noch bei einem anderen Status 4xx ausser dem429. Das ist ein Fehler Ihres Aufrufs: Protokollieren Sie ihn als zu behebenden Fehler, und behandeln Sie die Übermittlung als nicht geprüft: Lehnen Sie sie ab. - Der 429 ist eine Wahl.
Retry-Aftergibt die Wartezeit in Sekunden an. Mit einem Test-Secret kann ein429auch sagen, dass Ihre Test-Secrets ihre 1’000 Aufrufe des Tages aufgebraucht haben, oder die des Monats (Grenzen): Er dauert dann bis zur nächsten Mitternacht UTC, oder bis zum Ersten des nächsten UTC-Monats. Unsere Beispiele lassen standardmässig durch, wie bei einem Ausfall. Aber ein Angreifer kann einen429durch Masse auslösen: Der Weg ist pro Schlüssel begrenzt, und eine Flut von Übermittlungen auf Ihrem Formular erreicht diese Grenze, für alle Ihre Besucher, solange sie dauert; seine Übermittlungen kommen dann auch durch. Für ein sensibles Formular lehnen Sie bei einem429ab (deny): Das ist die schützende Wahl, um den Preis, während einer Überlastung legitime Besucher abzulehnen, die es nachRetry-Aftererneut versuchen. Das Standardverhalten wird durch eine Konstante im Node-Beispiel eingestellt. Ein503mitRetry-Afterist eine Lastabwehr: Die Instanz hat ihre Aufnahmekapazität erreicht, und ein Dritter kann das durch Masse auslösen, wie den429. Die Beispiele behandeln ihn wie einen Ausfall; für ein sensibles Formular lehnen Sie auch bei diesem503ab, mit demselben Wert wie für den429. - Ein fehlendes oder abgelehntes Secret fällt nicht unter diese Regel: Die Antwort ist eine Ablehnung mit
200(deny). Protokollieren Siemissing-input-secretundinvalid-input-secretals Konfigurationsfehler: Alle Ihre Besucher werden abgelehnt, solange sie andauern, und nichts anderes geht kaputt.
Während eines Ausfalls durchzulassen, ist eine Wahl: Bots können damit durchkommen. Das ist der Preis dafür, nie einen Besucher wegen Antisy zu blockieren.
Beispiele nach Sprache: PHP, Python, Go
Die Prüfung ist ein HTTP-Aufruf: keine Bibliothek zu installieren. Hier dasselbe Beispiel in PHP, in Python und in Go, mit denselben Regeln wie die Beispiele mit curl und Node im Schnellstart.
Was jedes Beispiel tut
- Es prüft das Token vor dem Aufruf. Ein vorhandenes Token ist eine Zeichenkette mit 1 bis 2048 druckbaren ASCII-Zeichen; sonst kontaktiert das Beispiel Antisy nicht und lehnt ab, wie Antisy es tun würde. Ein leeres Token geht, wie es ist: Antisy weiss, ob die Website ein Token erwartet.
- Es ruft
POST /v1/siteverifyauf, mit einem Formular-Body, dersecretundresponseträgt, und einem Zeitlimit von 3 Sekunden. Das Secret kommt aus der UmgebungsvariableANTISY_SECRET: nie fest im Code, nie als Argument der Befehlszeile, nie in einem Header. - Es liest nur
success:trueist die einzige Annahme. Eine unlesbare Antwort ist eine nicht geprüfte Übermittlung, also abgelehnt. - Es lässt nur durch, wenn Antisy nicht antwortet: Netzfehler, Zeitlimit überschritten, Antwort
5xx. Es protokolliert jedes Mal. - Es lässt nie durch bei einem Fehler Ihres Aufrufs:
400,401,413,415und jeder andere4xx, noch bei einer Weiterleitung3xx, der es nicht folgt: Eine Weiterleitung würde den Body samt Secret an eine andere Adresse wiederholen.
Der 429 ist eine Wahl, die bei Ihnen liegt: Eine Konstante am Anfang jedes Beispiels stellt ihn ein, standardmässig allow. Für ein sensibles Formular setzen Sie deny; die Seite wenn die API nicht antwortet sagt warum. Die Beispiele behandeln jeden 5xx wie einen Ausfall; um auch bei einem 503 mit Retry-After abzulehnen, behandeln Sie ihn vor dem Fall der 5xx, mit demselben Wert.
Die Beispiele sind die der Anleitung der API. Die Tests von Antisy lassen sie gegen einen lokalen Ersatzserver laufen, mit denselben Fällen: Antwort angenommen, abgelehnt, Ausfall, 429, Fehler Ihres Aufrufs, unlesbare Antwort, überschrittenes Zeitlimit und Weiterleitungen.
PHP
Mit der Erweiterung curl von PHP (curl_init) und PHP 8 oder neuer: Die Signatur der Funktion verwendet den Typ mixed.
<?php
/**
* Vérifie le jeton Antisy (mode simple). Rend le verdict : "allow" ou "deny".
*
* - jeton vide ou absent : envoyé tel quel, Antisy décide ; jeton non vide inutilisable : "deny", sans appel ;
* - Antisy ne répond pas (réseau, délai, 5xx) : "allow" et on journalise (fail-open) ;
* - 429 : ANTISY_ON_RATE_LIMIT ;
* - tout autre statut que 200 (400, 401, 413, 415...) : erreur de VOTRE appel, journalisée,
* tentative non vérifiée : "deny". Jamais "allow".
*/
const ANTISY_ON_RATE_LIMIT = 'allow'; // 'deny' für ein sensibles Formular: Ein Angreifer kann einen 429 auslösen
function antisy_verdict(mixed $token): string
{
if ($token === null) {
$token = ''; // fehlendes Feld: wie leer behandelt
}
// Leer: unverändert gesendet, Antisy entscheidet (Erfassung an: deny; aus: die Engine entscheidet).
// Nicht leer: 1 bis 2’048 druckbare ASCII-Zeichen; /D: « $ » duldet keinen abschliessenden Zeilenumbruch.
if ($token !== '' && (!is_string($token) || !preg_match('/^[\x20-\x7e]{1,2048}$/D', $token))) {
return 'deny'; // ein Formular-Array, ein zu langes oder präpariertes Token: was Antisy antworten würde
}
$ch = curl_init('https://api.antisy.com/v1/siteverify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3, // Sekunden; danach fail-open
CURLOPT_FOLLOWLOCATION => false, // keiner Weiterleitung folgen (das ist der Standard, ausgeschrieben, damit sie niemand einschaltet): Eine 3xx ist ein Fehler IHRES Aufrufs
CURLOPT_POSTFIELDS => http_build_query([
'secret' => getenv('ANTISY_SECRET'), // siteverify-Secret; nie fest im Code und nie beim Client
'response' => $token,
]),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$error = curl_error($ch);
curl_close($ch);
// Einziger Fall, in dem durchgelassen wird: Antisy antwortet nicht.
if ($body === false || $status >= 500) {
error_log("Antisy injoignable, envoi laissé passer (fail-open): {$error} (HTTP {$status})");
return 'allow';
}
if ($status === 429) {
error_log('Antisy 429 (voie saturée): ' . ANTISY_ON_RATE_LIMIT);
return ANTISY_ON_RATE_LIMIT;
}
if ($status !== 200) {
error_log("Antisy HTTP {$status} : erreur de l'appel, à corriger ; tentative non vérifiée");
return 'deny';
}
$result = json_decode($body, true);
if (is_array($result) && is_bool($result['success'] ?? null)) {
if ($result['success']) {
return 'allow'; // die einzige Annahme
}
return 'deny'; // success false: Ablehnung (das Ergebnis ist « deny »)
}
error_log('Réponse Antisy illisible, tentative non vérifiée');
return 'deny';
}// Im Handler Ihres Kontaktformulars:
$verdict = antisy_verdict($_POST['antisy-token'] ?? '');
if ($verdict === 'allow') {
// die Nachricht veröffentlichen / speichern
} else {
// deny: allgemeine Ablehnung, ohne Begründung
}Python
Nur die Standardbibliothek. urllib folgt standardmässig einer Weiterleitung 301, 302 oder 303: Das Beispiel installiert einen Opener, der keiner folgt.
import http.client
import json
import logging
import os
import re
import urllib.error
import urllib.parse
import urllib.request
API = "https://api.antisy.com/v1/siteverify"
# 429: "allow" (Standard, wie beim Node-Kit); "deny" für ein sensibles Formular, denn ein
# Angreifer kann einen 429 durch Masse auslösen.
ON_RATE_LIMIT = "allow"
# 1 bis 2’048 druckbare ASCII-Zeichen; `fullmatch` (und nicht `$`, das einen abschliessenden Zeilenumbruch duldet).
USABLE_TOKEN = re.compile(r"[\x20-\x7e]{1,2048}")
class _NoRedirect(urllib.request.HTTPRedirectHandler):
"""Aucun suivi de redirection : urllib suit un 301, 302 ou 303 par défaut ; la réponse 3xx est alors une erreur de VOTRE appel."""
def redirect_request(self, *args, **kwargs):
return None
_OPENER = urllib.request.build_opener(_NoRedirect)
def antisy_verdict(token) -> str:
"""Rend le verdict Antisy : "allow" ou "deny".
- jeton vide ou absent : envoyé tel quel, Antisy décide ; jeton non vide inutilisable : "deny", sans appel ;
- Antisy ne répond pas (réseau, délai, 5xx) : "allow" et on journalise (fail-open) ;
- 429 : ON_RATE_LIMIT ;
- tout autre statut que 200 (400, 401, 413, 415...) : erreur de VOTRE appel, journalisée,
tentative non vérifiée : "deny". Jamais "allow".
"""
if token is None:
token = "" # fehlendes Feld: wie leer behandelt
# Leer: unverändert gesendet, Antisy entscheidet (Erfassung an: deny; aus: die Engine entscheidet).
if token != "" and (not isinstance(token, str) or USABLE_TOKEN.fullmatch(token) is None):
return "deny" # zu lang, präpariert oder keine Zeichenkette: was Antisy antworten würde
data = urllib.parse.urlencode(
{
"secret": os.environ["ANTISY_SECRET"], # siteverify-Secret; nie beim Client
"response": token,
}
).encode()
try:
with _OPENER.open(urllib.request.Request(API, data=data), timeout=3) as response:
body = response.read()
except urllib.error.HTTPError as error:
if error.code >= 500:
logging.warning("Antisy HTTP %s, envoi laissé passer (fail-open)", error.code)
return "allow"
if error.code == 429:
logging.warning("Antisy 429 (voie saturée) : %s", ON_RATE_LIMIT)
return ON_RATE_LIMIT
logging.error("Antisy HTTP %s : erreur de l'appel, à corriger ; tentative non vérifiée", error.code)
return "deny"
except (urllib.error.URLError, http.client.HTTPException, OSError) as error:
# Netz, Zeitlimit, DNS, RemoteDisconnected, ConnectionResetError, IncompleteRead: Antisy hat
# nicht geantwortet (URLError, TimeoutError und ConnectionError sind OSError; sie sind für
# Lesende genannt). Das ist, neben dem 5xx, der einzige Fall, in dem durchgelassen wird.
logging.warning("Antisy injoignable (%s), envoi laissé passer (fail-open)", error)
return "allow"
try:
result = json.loads(body)
success = result.get("success")
except (ValueError, AttributeError):
success = None
if success is True:
return "allow" # die einzige Annahme
if success is False:
return "deny"
logging.error("Réponse Antisy illisible, tentative non vérifiée")
return "deny"# Im Handler Ihres Kontaktformulars:
verdict = antisy_verdict(form.get("antisy-token", ""))
if verdict == "allow":
pass # die Nachricht veröffentlichen / speichern
else:
pass # deny: allgemeine Ablehnung, ohne BegründungGo
Nur die Standardbibliothek. Der HTTP-Client ist Ihr eigener, mit einem Zeitlimit von 3 Sekunden: Das von http.DefaultClient ist unendlich. Die Prüfung des Tokens ist eine Schleife, weil die regulären Ausdrücke von Go einen Wiederholungszähler über 1’000 ablehnen.
// Package antisy prüft ein Antisy-Token im einfachen Modus: Verdict gibt "allow" oder "deny" zurück. Dieselben Regeln wie in den Beispielen oben.
package antisy
import (
"encoding/json"
"io"
"log"
"net/http"
"net/url"
"os"
"time"
)
const apiURL = "https://api.antisy.com/v1/siteverify"
// 429: "allow" (Standard, wie beim Node-Kit); "deny" für ein sensibles Formular, denn ein
// Angreifer kann einen 429 durch Masse auslösen.
const onRateLimit = "allow"
// 1 bis 2’048 druckbare ASCII-Zeichen (0x20 bis 0x7E). Eine Schleife und kein regulärer Ausdruck: Die von Go lehnen einen
// Wiederholungszähler über 1’000 ab (`{1,2048}` kompiliert nicht), und ein abschliessender Zeilenumbruch kommt auch nicht durch.
func usableToken(token string) bool {
if len(token) < 1 || len(token) > 2048 {
return false
}
for i := 0; i < len(token); i++ {
if token[i] < 0x20 || token[i] > 0x7e {
return false
}
}
return true
}
// Ein eigener Client mit einem Zeitlimit von 3 s (das von http.DefaultClient ist unendlich); danach fail-open.
// Keine Weiterleitung: Ein 307 würde den Body samt Secret an eine andere Adresse wiederholen.
var client = &http.Client{
Timeout: 3 * time.Second,
CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse },
}
// Verdict gibt das Antisy-Ergebnis zurück: "allow" oder "deny".
//
// - Token leer oder fehlend: unverändert gesendet, Antisy entscheidet; nicht leeres, unbrauchbares Token: "deny", ohne Aufruf;
// - Antisy antwortet nicht (Netz, Zeitlimit, abgebrochene Antwort, 5xx): "allow", mit Protokolleintrag (fail-open);
// - 429: onRateLimit;
// - jeder andere Status als 200 (400, 401, 413, 415 ...): Fehler IHRES Aufrufs, protokolliert,
// Versuch nicht geprüft: "deny". Nie "allow".
func Verdict(token string) string {
// Leer: unverändert gesendet, Antisy entscheidet (Erfassung an: deny; aus: die Engine entscheidet).
if token != "" && !usableToken(token) {
return "deny" // zu lang oder präpariert: was Antisy antworten würde
}
response, err := client.PostForm(apiURL, url.Values{
"secret": {os.Getenv("ANTISY_SECRET")}, // siteverify-Secret; nie fest im Code und nie beim Client
"response": {token},
})
if err != nil {
// Netz, DNS, Zeitlimit überschritten: Antisy hat nicht geantwortet. Neben dem 5xx der einzige Fall, in dem durchgelassen wird.
// err kann die URL des Aufrufs nennen, nie den Body: Das Secret steht nicht im Protokoll.
log.Printf("antisy injoignable, envoi laissé passer (fail-open): %v", err)
return "allow"
}
defer response.Body.Close()
body, readErr := io.ReadAll(io.LimitReader(response.Body, 1<<20))
switch {
case response.StatusCode >= 500:
log.Printf("antisy HTTP %d, envoi laissé passer (fail-open)", response.StatusCode)
return "allow"
case response.StatusCode == http.StatusTooManyRequests:
log.Printf("antisy 429 (voie saturée) : %s", onRateLimit)
return onRateLimit
case response.StatusCode != http.StatusOK:
log.Printf("antisy HTTP %d : erreur de l'appel, à corriger ; tentative non vérifiée", response.StatusCode)
return "deny" // 400, 401, 413, 415 ... nie « allow »
}
if readErr != nil {
log.Printf("antisy : réponse coupée (%v), envoi laissé passer (fail-open)", readErr)
return "allow" // Antisy hat nicht fertig geantwortet: Das ist ein Ausfall, keine Ablehnung
}
var result struct {
Success *bool `json:"success"`
}
if json.Unmarshal(body, &result) != nil || result.Success == nil {
log.Printf("antisy : réponse illisible, tentative non vérifiée")
return "deny"
}
if *result.Success {
return "allow" // die einzige Annahme
}
return "deny"
}// Im Handler Ihres Kontaktformulars (net/http):
func contact(w http.ResponseWriter, r *http.Request) {
// PostFormValue gibt "" zurück, wenn das Feld fehlt: wie leer behandelt.
if antisy.Verdict(r.PostFormValue("antisy-token")) != "allow" {
http.Error(w, "refusé", http.StatusForbidden) // deny: allgemeine Ablehnung, ohne Begründung
return
}
// die Nachricht veröffentlichen / speichern
}Eine andere Sprache
Übernehmen Sie, was die Beispiele tun, nicht ihre Syntax.
- Der Body ist ein Formular (
application/x-www-form-urlencoded), dassecretundresponseträgt, oder ein JSON-Objekt mit denselben Feldern. - Kein Header
Authorization: Seine Anwesenheit schaltet die Anfrage in einen anderen Modus (die Anfrage). - Keiner Weiterleitung folgen, und ein Zeitlimit von 3 Sekunden.
- Dieselben Fälle, in derselben Reihenfolge: das geprüfte Token, der Aufruf, der Ausfall, der durchlässt, der Fehler Ihres Aufrufs, der ablehnt,
success, das entscheidet.
Login und Registrierung
Diese Beispiele eignen sich für Formulare mit geringem Risiko. Sie binden das Token nicht an ein Konto: Verwenden Sie sie nicht für ein Login oder eine Registrierung. Das Node-SDK ist noch nicht veröffentlicht; die Schritt-für-Schritt-Anleitung sagt, was diese Dokumentation abdeckt.
Den tatsächlichen Ausgang eines Versuchs melden (optional)
Antisy misst seine Regeln an dem, was tatsächlich geschehen ist: eine Registrierung, deren Adresse bestätigt ist, ein Betrug, den Sie festgestellt haben. Ohne das Node-Kit sagen Sie es mit demselben Secret wie für die Prüfung, in einem Aufruf. Das ist Messung, nie eine Entscheidung: Das Signal erzeugt kein Ergebnis, ändert nichts direkt, und die Antwort trägt keines. Es nicht zu senden, kostet Ihren Schutz nichts.
POST https://api.antisy.com/v1/feedback, ohne Header Authorization (seine Anwesenheit schaltet in den Modus des SDK, signiert und verschlüsselt), mit einem Body application/x-www-form-urlencoded oder application/json. Drei Felder, und nichts anderes: Ein Feld mehr ist ein 400 (bad-request).
- secret
- Dasselbe Verifizierungs-Secret wie für
/v1/siteverify, im Body und nirgends sonst. - event_id
- Die
event_id, diesiteverifyfür diese Prüfung zurückgegeben hat (evt_gefolgt von 26 Zeichen). Bewahren Sie sie mit dem Objekt auf, das sie beschreibt, der Zeile der Registrierung oder der Nachricht: Nur so können Sie später melden. - outcome
success,failure,account_confirmed_fraudoderfalse_positive. Die ersten drei beschreiben den Versuch;false_positivesagt, dass Ihnen das Ergebnis von Antisy falsch erschien, und wird getrennt gezählt. Senden Sie nur, was Sie wissen: ein Konto, dessen Adresse bestätigt ist, nicht ein Konto, das nur angelegt wurde.
# ANTISY_SECRET: Ihr Verifizierungs-Secret, aus der Umgebung, nie fest im Code.
# ANTISY_EVENT_ID: die event_id, die siteverify für diese Verifizierung zurückgegeben hat.
# Erst nach der Antwort an Ihren Besucher ausführen. Kein -L: Weiterleitungen werden nicht gefolgt.
printf 'secret=%s' "$ANTISY_SECRET" | curl -sS --max-time 3 -w '\n%{http_code}\n' \
https://api.antisy.com/v1/feedback \
-d @- \
--data-urlencode event_id="$ANTISY_EVENT_ID" \
--data-urlencode outcome=success{"success":true,"error-codes":[]}
200Der Body der Antwort hat immer zwei Schlüssel: success und error-codes. Hier sagt success nur « Meldung angenommen », kein Ergebnis; es gibt nie ein Ergebnis, einen Score, einen Grund oder eine event_id. Die Status sind echte Status, anders als bei siteverify: Ein 4xx ist nie zu wiederholen, ein 429 oder ein 5xx später, ein- oder zweimal. Keine Entscheidung hängt von der Antwort ab: Protokollieren Sie sie.
200error-codesleer: angenommen, oder schon gleich angenommen (derselbe Ausgang für dasselbe Ereignis: nichts wird neu geschrieben), oder beiseitegelegt, ohne etwas zu speichern (Test-Secret, Website oder Organisation gesperrt).401missing-input-secretoderinvalid-input-secret: Secret fehlt; unbekannt, widerrufen, von einer geschlossenen Website, oder Bewertungsschlüssel (dieselbe Antwort für alle). Korrigieren Sie die Konfiguration.400missing-input-event- event_id fehlt: Korrigieren Sie den Aufruf.
400invalid-input-event- event_id fehlerhaft, oder ein Ereignis, das dieses Secret nicht melden kann (nicht vorhanden, von einer anderen Website, aus einem anderen Weg entstanden, oder ohne Speicherung). Eine einzige Ablehnung für all diese Fälle. Nicht erneut versuchen.
400missing-input-outcome- outcome fehlt: Korrigieren Sie den Aufruf.
400invalid-input-outcome- outcome ausserhalb der Liste: Korrigieren Sie den Aufruf.
409outcome-conflict- Für dieses Ereignis wurde schon ein anderer Ausgang gemeldet. Nicht erneut versuchen.
410event-expired- Das Ereignis ist älter als 30 Tage. Nicht erneut versuchen.
422daily-limit-reached- Tagesobergrenze dieses Modus erreicht. Nicht erneut versuchen; machen Sie morgen weiter (UTC-Tag), wenn der Ausgang für Sie zählt.
400,405,413,415bad-request: unbekanntes Feld (auch eine Notiz oder ein Datum), unlesbarer Body oder einer von mehr als 16 KiB, Methode oder Content-Type nicht gelesen.429,5xxrate-limitedmitRetry-After, oderinternal-error(503mitRetry-Afterbei Lastabwehr). Versuchen Sie es später erneut.
Die Grenzen
- Das Ereignis muss aus einer Prüfung
siteverifyim einfachen Modus dieser Website entstanden und jünger als 30 Tage sein. Ein einziger Ausgang pro Ereignis. - Manche Antworten von
siteverifytragen eineevent_id, die kein gespeichertes Ereignis bezeichnet: abgelehntes Secret, gesperrte Website, Test-Token, Body von mehr als 16 KiB, Website der Stufe Kostenlos über ihrem Kontingent (over_quotainflags). Sie zu melden, ergibtinvalid-input-event. Ein Ereignis des signierten Wegs ist hier nicht meldbar. - Der Modus hat eine eigene Tagesobergrenze, pro Website (ein Zwanzigstel der Prüfungen des Tages, mindestens 20; zwei Annahmen, während des Pilots zu überprüfen), getrennt von der des signierten Kits gezählt. Darüber:
422. Die Obergrenze lässt nicht den Ausgang jeder Prüfung durch: Senden Sie zuerst, was am meisten lehrt,failureundaccount_confirmed_fraud, dannsuccess, wenn Platz bleibt. - Das Secret ist das von
siteverify: Ein gestohlenes Secret würde erlauben, die Messung Ihrer Ereignisse der letzten 30 Tage zu verfälschen und die Tagesobergrenze dieses Modus auszuschöpfen, also Ihre echten Ausgänge zu verhindern. Es ändert kein Ergebnis und liest nichts. Es im Dashboard zu ersetzen, schaltet es ab. - Rufen Sie die Route von Ihrem Server auf, nachdem Sie dem Besucher geantwortet haben, mit einem Zeitlimit von 3 Sekunden und ohne einer Weiterleitung zu folgen; ein einziger erneuter Versuch, später, bei einem Netzfehler, einem
429oder einem5xx.
Grenzen
- Die Route hat ihre eigenen Obergrenzen der Rate, pro Adresse und pro Schlüssel. Darüber:
429undRetry-After. Dieser Status kann durch Masse ausgelöst werden: siehe weiter oben. - Die Test-Secrets teilen sich 1’000 Aufrufe pro Tag für die ganze Organisation, über alle Websites (UTC-Tag). Darüber:
429rate-limited, mit einemRetry-After, das bis zur nächsten Mitternacht UTC läuft. Sie teilen sich auch, Stand heute, 2’500 Aufrufe pro Monat (UTC-Monat): Darüber derselbe429, dessenRetry-Afterbis zum Ersten des nächsten UTC-Monats läuft. Siehe die Testschlüssel. - Ein Body von mehr als 16 KiB, oder ein
responsevon mehr als 2048 Zeichen, erhält die Antwort eines gefälschten Tokens. Senden Sie das nicht: Prüfen Sie das Token vor dem Aufruf.