Optioneel. Een DNS-filter, een adblocker of een netwerk dat de host van Korzen blokkeert, houdt de tag, zijn beacon en de uitdagingspagina tegen. Die bezoekers komen nog steeds door, beoordeeld op alleen wat je server stuurt, maar op een route die het token van de tag vraagt, komen ze niet verder. De first-party-modus serveert alle drie vanaf een pad van je eigen domein, /kz tenzij je een ander kiest, en stuurt ze door naar Bot Protection met het adres van de bezoeker. Niets blokkeert een pad van een site zonder de site te blokkeren.
Er zijn twee manieren om het pad te serveren, en je kunt ze allebei gebruiken:
| De manier | Wat je aanzet | Wie /kz serveert |
|---|---|---|
| Alleen de SDK | firstParty: true in Node, FirstParty: true in Go | je server |
| Alleen de Worker | KORZEN_FIRST_PARTY = "1" en een route voor /kz/* | je Cloudflare Worker |
| De Worker en de SDK | allebei, met hetzelfde pad | de Worker; je server stuurt uitgedaagde bezoekers naar hem |
Op elke manier laadt de pagina de tag vanaf je pad in plaats van vanaf de host van Korzen. De tag haalt zijn adres uit zijn eigen src, dus elke request die hij doet gaat ook naar /kz:
<script src="/kz/tag.js" data-site-key="YOUR_SITE_KEY" async></script>
De modus zit in elke SDK: Node (en zijn Worker), Go, Python, PHP, Java en .NET, elk met zijn optie in de README. Een client die je naar een frameworkgids schreef, heeft geen forwarder: gebruik daar de SDK of, achter Cloudflare, de Worker op zichzelf, die de modus aan een origin in elke taal geeft.
Alleen de SDK
Je server serveert het pad. Geef de middleware die Bot Protection al vraagt de optie, en geef het pad een eigen handler met dezelfde opties. De client moet door createClient gemaakt zijn, met je API-sleutel: de forwarder stuurt die bij elke request naar Korzen.
// 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))
- Wat je aanzet.
firstParty: trueopprotectofwithKorzen(alleen aan als hettrueis); in GoOptions.FirstParty. Daarna wordt desrcvan de tag op je pagina's/kz/tag.js. Het adres van de bezoeker wordt gelezen zoals de beslissing het leest: de optieip, in GoOptions.IP. - Een adres dat de bezoeker niet kan schrijven. Korzen vertrouwt het adres dat de forwarder met je sleutel stuurt, dus de optie
ipmoet er een lezen dat de bezoeker niet kan zetten:ipFrom.vercelalleen op Vercel,ipFrom.cloudflare(Go:korzen.CloudflareIP) alleen als je server alleen verkeer van Cloudflare aanneemt,ipFrom.lastForwardedachter je eigen load balancer of nginx. Een header die de bezoeker kan schrijven laat een script het adres kiezen dat Korzen beoordeelt. - Wat er verandert voor de bezoeker. Niets wat hij ziet. Zijn browser laadt de tag en stuurt zijn beacon naar je domein, dus een bezoeker van wie het netwerk Korzen blokkeert, wordt beoordeeld met het bewijs van de tag en kan een actie doen die het token vraagt. Requests onder het pad worden nooit beoordeeld en bereiken je handlers nooit; elk ander pad wordt beoordeeld zoals voorheen.
- De uitdagingspagina. Een uitgedaagde paginalading gaat naar
/kz/challenge?c=…&r=…op je domein in plaats van dat van Korzen, en je server stuurt de pagina, haar bestanden en haar verzending door. Dezelfde puzzel, en de bezoeker komt terug op de pagina die hij opvroeg. - Fail-open. Is Bot Protection traag, onbereikbaar of plat, dan antwoordt elke request onder het pad
503met een lege body, en laat de tag dat signaal vallen; de pagina en je andere routes wachten nergens op. Fail-open - Zo zie je dat het werkt.
curl -I https://shop.example/kz/tag.jsantwoordt200, en het netwerkpaneel van de browser toont de requests van de tag naar je eigen domein. Zo zie je dat het werkt
Alleen de Worker
Je Cloudflare Worker serveert het pad, zonder wijziging aan je server, voor een origin in elke taal. Zet de Worker op zoals Cloudflare Workers laat zien, zet dan de modus aan en voeg een route voor het pad toe:
# 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
- Wat je aanzet.
KORZEN_FIRST_PARTYop1oftrue(elke andere waarde dan0offalselaat hem uit, met een waarschuwing in de log van de Worker), een route voorshop.example/kz/*, en desrcvan de tag op je pagina's als/kz/tag.js. Het adres van de bezoeker isCF-Connecting-IP, dat Cloudflare zet. - Wat er verandert voor de bezoeker. Niets wat hij ziet. De tag en zijn beacon gaan naar je domein en worden beantwoord aan de edge van Cloudflare; je origin ziet die requests nooit. De routes van de Worker worden beoordeeld zoals voorheen.
- De uitdagingspagina. Een paginalading die de Worker uitdaagt, gaat naar
/kz/challengeop je domein, die de Worker serveert. - Fail-open. Net als bij de SDK: een
503met een lege body voor alleen die request, en alle andere gaan door naar je origin. Fail-open - Zo zie je dat het werkt. Zoals hieronder; en
npx wrangler tailtoont de requests onder/kz, terwijl de accesslog van je origin er geen enkele toont. Zo zie je dat het werkt
De Worker en de SDK
Staat er een Worker voor je site en draait de SDK in je applicatie (voor de context die alleen je applicatie kent), zet de modus dan in allebei aan, met hetzelfde pad.
- Wat je aanzet. De Worker zoals hierboven, met zijn route voor
/kz/*, enfirstParty: true(Go:FirstParty: true) op de SDK erachter. De Worker beantwoordt/kz/*zelf, dus de SDK ziet die requests nooit. - Wat er verandert voor de bezoeker. Hetzelfde als met alleen de Worker: de tag, zijn beacon en de uitdagingspagina komen van je domein, beantwoord aan de edge.
- De uitdagingspagina. De
firstPartyvan de SDK stuurt de bezoekers die hij uitdaagt naar/kz/challengein plaats van naar de host van Korzen, en de Worker serveert die pagina. Zonder gaat een bezoeker die de SDK uitdaagt naar de host van Korzen, die zijn netwerk kan blokkeren. - Fail-open. Wie het pad serveert, geeft zelf op en antwoordt
503; geen van beide houdt de ander op. Laten de routes van de Worker/kz/*weg, of verdwijnt de Worker, dan serveert de SDK het pad zelf: geef hem achter Cloudflare danip: ipFrom.cloudflare(Go:korzen.CloudflareIP). - Zo zie je dat het werkt. Zoals hieronder;
npx wrangler tailtoont de requests onder/kz, en de log van je server toont er geen.
Wat het pad serveert
De forwarder, de SDK of de Worker, beantwoordt deze en verder niets:
| Op je domein | Wat het is |
|---|---|
GET /kz/tag.js | de tag, met de cacheheaders van Korzen |
GET /kz/n, POST /kz/s | de nonce van de tag en zijn beacon (een body van hoogstens 64 KiB) |
GET /kz/ping | door de forwarder zelf met 204 beantwoord, nooit doorgestuurd |
GET en POST /kz/challenge, GET /kz/challenge/wait | de uitdagingspagina en haar verzending (hoogstens 16 KiB) |
GET /kz/static/… | het script, de stijl en de lettertypen van de uitdagingspagina |
Elk ander pad onder /kz is een 404, en een bekend pad met een andere methode een 405; geen van beide bereikt Bot Protection, dus het pad is nooit een open proxy. Naar Korzen stuurt de forwarder de eigen headers van de browser van een korte lijst (User-Agent, Accept, Accept-Language, Content-Type, Origin, Sec-Fetch-*, de client hints, If-None-Match), je API-sleutel als bearer en het adres van de bezoeker. Nooit een cookie, de Authorization van de browser of een X-Forwarded-*. Wat terugkomt houdt de cache- en beveiligingsheaders van Korzen, nooit een Set-Cookie.
Korzen neemt het adres van de bezoeker alleen aan uit een request op deze routes die je API-sleutel draagt, en op de beacon alleen voor je eigen site key; al het andere wordt geweigerd met 403. Je sleutel bereikt de browser nooit.
De cookie _kz van de tag en zijn opslag blijven op je domein, zoals voorheen; de gegevens die Korzen ontvangt zijn dezelfde. Een paar stukken bewijs die Korzen alleen leest als de browser rechtstreeks met Korzen verbindt, ontbreken via een forwarder; de rest van het bewijs van de tag komt aan, en niets van wat ontbreekt telt tegen een bezoeker.
Een ander pad
firstPartyPath (Go: Options.FirstPartyPath; de Worker: KORZEN_FIRST_PARTY_PATH) noemt een ander pad, bijvoorbeeld zodra een blokkeerlijst /kz leert. Het begint met /, eindigt zonder, en is hoogstens 64 tekens in segmenten van A-Z a-z 0-9 . _ ~ -. Een pad dat niet te lezen is, wordt één keer gelogd, en de modus blijft uit. Gebruik hetzelfde pad in de src van de tag, in de SDK en in de Worker.
Fail-open
Het pad houdt je pagina en je andere routes nooit op:
- Elke doorgestuurde request geeft zelf op: na 1 s voor een
GET, 2,5 s voor eenPOST. Een timeout, een netwerkfout, een antwoord boven 4 MiB of een fout in de forwarder is een503met een lege body enCache-Control: no-store; redirects worden niet gevolgd. De eigen4xxen5xxvan Bot Protection gaan ongewijzigd door. - Zonder het adres van de bezoeker (de optie
ipleest er geen) antwoorden de nonce, de beacon en de uitdaging503; de tag en de bestanden van de uitdagingspagina worden nog steeds geserveerd. - De tag laat dat signaal dan vallen, zoals wanneer de host van Korzen plat ligt. Een tag die niets meldde is nooit bewijs van een bot: de bezoeker wordt beoordeeld op wat je server stuurt.
Zo zie je dat het werkt
curl -I https://shop.example/kz/tag.jsantwoordt200, encurl -I https://shop.example/kz/pingantwoordt204.- In de ontwikkelaarstools van de browser toont het netwerkpaneel op een pagina met de tag
/kz/tag.js,/kz/n,/kz/pingen/kz/sop je eigen domein, beantwoord met200of204, en geen enkele request naar de host van Korzen. - Doorloop een beschermde actie en klik dan op Controleer je integratie op de Set-up-pagina: Het token van de tag in die call staat op Gezien. Je beslissingen verschijnen zoals voorheen op de pagina Beslissingen van het dashboard.
- Met een
Content-Security-Policykan de host van Korzen eruit:script-src 'self'; connect-src 'self'; worker-src blob:is genoeg voor de tag. De tag
Veelgemaakte fouten
- De tag laadt nog vanaf de host van Korzen: de modus serveert het pad, maar alleen de
srcvan de tag stuurt de browser erheen. - Een body parser vóór de forwarder in Express: de body van de beacon wordt gelezen voordat de forwarder hem krijgt. Monteer hem vóór elke parser, of alleen op het pad.
- De Worker met
KORZEN_FIRST_PARTYmaar zonder route voor/kz/*: de requests bereiken je origin, die404antwoordt, tenzij de SDK het pad daar serveert. - Twee paden: de Worker op het ene en de SDK op een ander. De SDK stuurt uitgedaagde bezoekers dan naar een pad dat de Worker niet serveert.
/v1/decidemet de hand aanroepen: zijnchallenge.urlis altijd de host van Korzen. Alleen de SDK's en de Worker sturen de bezoeker naar je pad.