Korzen
Bot Protection
In questa documentazione

Modalità first-party

Il tag, il suo beacon e la pagina di sfida serviti dal tuo dominio, da un SDK, da un Cloudflare Worker o da entrambi, per i visitatori la cui rete blocca Korzen.

Facoltativa. Un filtro DNS, un ad blocker o una rete che blocca l'host di Korzen ferma il tag, il suo beacon e la pagina di sfida. Quei visitatori passano comunque, giudicati solo su ciò che invia il tuo server, ma su una route che richiede il token del tag non possono passare. La modalità first-party serve tutti e tre da un percorso del tuo dominio, /kz se non ne scegli un altro, e li inoltra a Bot Protection con l'indirizzo del visitatore. Niente blocca un percorso di un sito senza bloccare il sito.

Ci sono due modi di servire il percorso, e puoi usarli entrambi:

Il modoCosa attiviChi serve /kz
Solo l'SDKfirstParty: true in Node, FirstParty: true in Goil tuo server
Solo il WorkerKORZEN_FIRST_PARTY = "1" e una route per /kz/*il tuo Cloudflare Worker
Il Worker e l'SDKentrambi, con lo stesso percorsoil Worker; il tuo server gli manda i visitatori sfidati

In ogni modo, la pagina carica il tag dal tuo percorso invece che dall'host di Korzen. Il tag prende il suo indirizzo dal proprio src, quindi ogni richiesta che fa va anch'essa a /kz:

<script src="/kz/tag.js" data-site-key="YOUR_SITE_KEY" async></script>

La modalità c'è in ogni SDK: Node (e il suo Worker), Go, Python, PHP, Java e .NET, ciascuno con la sua opzione nel README. Un client scritto da una guida di framework non ha un forwarder: lì usa l'SDK o, dietro Cloudflare, il solo Worker, che dà la modalità a un'origine in qualsiasi linguaggio.

Solo l'SDK

Il tuo server serve il percorso. Passa l'opzione al middleware che già interroga Bot Protection, e dai al percorso un handler suo con le stesse opzioni. Il client deve essere creato da createClient, con la tua chiave API: il forwarder la invia a Korzen con ogni richiesta.

// Express, with korzen.js as the Express guide sets it up
const options = { client: korzen, ip: (_get, req) => req.ip, firstParty: true };

app.use("/kz", protect(options)); // before any body parser: it answers /kz/... itself
app.use(express.urlencoded({ extended: false }));
app.post("/signup", protect(options), signup);

// Next.js: app/kz/[...path]/route.js serves the path
const kz = withKorzen(() => new Response(null, { status: 404 }), { client, ip: ipFrom.vercel, firstParty: true });
export { kz as GET, kz as POST };
o := korzen.Options{IP: korzen.RemoteIP, FirstParty: true}

mux.Handle("/kz/", bot.Protect(http.NotFoundHandler(), o)) // the path: Protect answers it itself
mux.Handle("POST /signup", bot.Protect(http.HandlerFunc(signup), o))
  • Cosa attivi. firstParty: true su protect o withKorzen (attiva solo quando è true); in Go, Options.FirstParty. Poi il src del tag nelle tue pagine diventa /kz/tag.js. L'indirizzo del visitatore si legge come lo legge la decisione: l'opzione ip, in Go Options.IP.
  • Un indirizzo che il visitatore non può scrivere. Korzen si fida dell'indirizzo che il forwarder invia con la tua chiave, quindi l'opzione ip deve leggerne uno che il visitatore non può impostare: ipFrom.vercel solo su Vercel, ipFrom.cloudflare (Go: korzen.CloudflareIP) solo se il tuo server riceve traffico solo da Cloudflare, ipFrom.lastForwarded dietro il tuo load balancer o nginx. Un header che il visitatore può scrivere lascia a uno script la scelta dell'indirizzo che Korzen giudica.
  • Cosa cambia per il visitatore. Niente che veda. Il suo browser carica il tag e invia il beacon al tuo dominio, quindi un visitatore la cui rete blocca Korzen viene giudicato con le prove del tag e può compiere un'azione che richiede il suo token. Le richieste sotto il percorso non vengono mai giudicate e non arrivano mai ai tuoi handler; ogni altro percorso viene giudicato come prima.
  • La pagina di sfida. Un caricamento di pagina sfidato va a /kz/challenge?c=…&r=… sul tuo dominio invece che su quello di Korzen, e il tuo server inoltra la pagina, i suoi file e il suo invio. La stessa sfida, e il visitatore torna alla pagina che aveva chiesto.
  • Fail-open. Quando Bot Protection è lento, non disponibile o irraggiungibile dal tuo server, ogni richiesta sotto il percorso risponde 503 con il corpo vuoto, e il tag lascia perdere quel segnale; la pagina e le altre route non aspettano nulla. Fail-open
  • Come capire che funziona. curl -I https://shop.example/kz/tag.js risponde 200, e il pannello di rete del browser mostra le richieste del tag verso il tuo dominio. Come capire che funziona

Solo il Worker

Il tuo Cloudflare Worker serve il percorso, senza modifiche al tuo server, per un'origine in qualsiasi linguaggio. Configura il Worker come mostra Cloudflare Workers, poi attiva la modalità e aggiungi una route per il percorso:

# wrangler.toml
routes = [
  { pattern = "shop.example/kz/*", zone_name = "shop.example" },
  { pattern = "shop.example/signup*", zone_name = "shop.example" },
]

[vars]
KORZEN_URL = "https://korzen.dev"
KORZEN_FIRST_PARTY = "1"
# KORZEN_FIRST_PARTY_PATH = "/kz"   # the path, /kz unless set
  • Cosa attivi. KORZEN_FIRST_PARTY a 1 o true (qualsiasi altro valore tranne 0 o false la lascia disattivata, con un avviso nel log del Worker), una route per shop.example/kz/*, e il src del tag nelle tue pagine come /kz/tag.js. L'indirizzo del visitatore è CF-Connecting-IP, che imposta Cloudflare.
  • Cosa cambia per il visitatore. Niente che veda. Il tag e il suo beacon vanno al tuo dominio, serviti all'edge di Cloudflare; la tua origine non vede mai quelle richieste. Le route del Worker vengono giudicate come prima.
  • La pagina di sfida. Un caricamento di pagina che il Worker sfida va a /kz/challenge sul tuo dominio, che serve il Worker.
  • Fail-open. Come per l'SDK: un 503 con il corpo vuoto solo per quella richiesta, e tutte le altre proseguono verso la tua origine. Fail-open
  • Come capire che funziona. Come sotto; e npx wrangler tail elenca le richieste sotto /kz, mentre il log degli accessi della tua origine non ne mostra nessuna. Come capire che funziona

Il Worker e l'SDK

Quando un Worker sta davanti al tuo sito e l'SDK gira nella tua applicazione (per il context che solo la tua applicazione conosce), attiva la modalità in entrambi, con lo stesso percorso.

  • Cosa attivi. Il Worker come sopra, con la sua route per /kz/*, e firstParty: true (Go: FirstParty: true) sull'SDK dietro di esso. Il Worker risponde da sé a /kz/*, quindi l'SDK non vede mai quelle richieste.
  • Cosa cambia per il visitatore. Lo stesso che con il solo Worker: il tag, il suo beacon e la pagina di sfida arrivano dal tuo dominio, serviti all'edge.
  • La pagina di sfida. Il firstParty dell'SDK manda i visitatori che sfida a /kz/challenge invece che all'host di Korzen, e il Worker serve quella pagina. Senza, un visitatore che l'SDK sfida va all'host di Korzen, che la sua rete può bloccare.
  • Fail-open. Chi serve il percorso rinuncia da sé e risponde 503; nessuno trattiene l'altro. Se le route del Worker lasciano fuori /kz/*, o il Worker viene tolto, l'SDK serve il percorso da sé: dietro Cloudflare, dagli allora ip: ipFrom.cloudflare (Go: korzen.CloudflareIP).
  • Come capire che funziona. Come sotto; npx wrangler tail elenca le richieste sotto /kz, e il log del tuo server non ne mostra nessuna.

Cosa serve il percorso

Il forwarder, l'SDK o il Worker, risponde a queste e a nient'altro:

Sul tuo dominioCos'è
GET /kz/tag.jsil tag, con gli header di cache di Korzen
GET /kz/n, POST /kz/sil nonce del tag e il suo beacon (un corpo di al massimo 64 KiB)
GET /kz/pingrisposto 204 dal forwarder stesso, mai inoltrato
GET e POST /kz/challenge, GET /kz/challenge/waitla pagina di sfida e il suo invio (al massimo 16 KiB)
GET /kz/static/…lo script, lo stile e i font della pagina di sfida

Qualsiasi altro percorso sotto /kz è un 404, e uno noto con un altro metodo un 405; nessuno dei due arriva a Bot Protection, quindi il percorso non è mai un proxy aperto. A Korzen il forwarder invia gli header del browser da una lista breve (User-Agent, Accept, Accept-Language, Content-Type, Origin, Sec-Fetch-*, i client hint, If-None-Match), la tua chiave API come bearer e l'indirizzo del visitatore. Mai un cookie, l'Authorization del browser o un X-Forwarded-*. Ciò che torna mantiene gli header di cache e di sicurezza di Korzen, mai un Set-Cookie.

Korzen accetta l'indirizzo del visitatore solo da una richiesta su queste route che porta la tua chiave API, e sul beacon solo per la tua site key; tutto il resto viene rifiutato con 403. La tua chiave non arriva mai al browser.

Il cookie _kz del tag e il suo storage restano sul tuo dominio, come prima; i dati che Korzen riceve sono gli stessi. Alcune prove che Korzen legge solo quando il browser si collega direttamente a Korzen mancano attraverso un forwarder; il resto delle prove del tag arriva, e niente di ciò che manca conta contro un visitatore.

Un altro percorso

firstPartyPath (Go: Options.FirstPartyPath; il Worker: KORZEN_FIRST_PARTY_PATH) indica un altro percorso, per esempio quando una lista di blocco impara /kz. Inizia con /, finisce senza, ed è di al massimo 64 caratteri in segmenti di A-Z a-z 0-9 . _ ~ -. Uno che non si legge viene registrato nel log una volta, e la modalità resta disattivata. Usa lo stesso percorso nel src del tag, nell'SDK e nel Worker.

Fail-open

Il percorso non trattiene mai la tua pagina né le altre route:

  • Ogni richiesta inoltrata rinuncia da sé: dopo 1 s per un GET, 2,5 s per un POST. Un timeout, un errore di rete, una risposta oltre i 4 MiB o un guasto del forwarder è un 503 con il corpo vuoto e Cache-Control: no-store; i redirect non vengono seguiti. I 4xx e 5xx di Bot Protection stesso passano così come sono.
  • Senza l'indirizzo del visitatore (l'opzione ip non ne legge nessuno), il nonce, il beacon e la sfida rispondono 503; il tag e i file della pagina di sfida vengono comunque serviti.
  • Il tag lascia allora perdere quel segnale, come quando l'host di Korzen non è disponibile. Un tag che non ha riferito non è mai una prova di un bot: il visitatore viene giudicato su ciò che invia il tuo server.

Come capire che funziona

  • curl -I https://shop.example/kz/tag.js risponde 200, e curl -I https://shop.example/kz/ping risponde 204.
  • Negli strumenti per sviluppatori del browser, su una pagina con il tag, il pannello di rete mostra /kz/tag.js, /kz/n, /kz/ping e /kz/s sul tuo dominio, con risposta 200 o 204, e nessuna richiesta all'host di Korzen.
  • Compi un'azione protetta e poi premi Verifica l'integrazione nella pagina Configurazione: Il token del tag in quella chiamata indica Rilevato. Le tue decisioni compaiono come prima nella pagina Decisioni della dashboard.
  • Con una Content-Security-Policy, l'host di Korzen può uscirne: script-src 'self'; connect-src 'self'; worker-src blob: basta per il tag. Il tag

Errori comuni

  • Il tag ancora caricato dall'host di Korzen: la modalità serve il percorso, ma solo il src del tag ci porta il browser.
  • Un body parser prima del forwarder in Express: il corpo del beacon viene letto prima che il forwarder lo riceva. Montalo prima di qualsiasi parser, o solo sul percorso.
  • Il Worker con KORZEN_FIRST_PARTY ma senza route per /kz/*: le richieste arrivano alla tua origine, che risponde 404 a meno che l'SDK non serva lì il percorso.
  • Due percorsi: il Worker su uno e l'SDK su un altro. L'SDK manda allora i visitatori sfidati a un percorso che il Worker non serve.
  • Chiamare /v1/decide a mano: il suo challenge.url è sempre l'host di Korzen. Solo gli SDK e il Worker mandano il visitatore al tuo percorso.