Facultatif. Un filtre DNS, un bloqueur de publicité ou un réseau qui bloque l'hôte de Korzen arrête le tag, son beacon et la page de défi. Ces visiteurs passent toujours, jugés sur ce que votre serveur envoie seul, mais sur une route qui exige le token du tag, ils ne peuvent pas passer. Le mode first-party sert les trois depuis un chemin de votre propre domaine, /kz sauf si vous en nommez un autre, et les transmet à Bot Protection avec l'adresse du visiteur. Rien ne bloque un chemin d'un site sans bloquer le site.
Il y a deux façons de servir le chemin, et vous pouvez utiliser les deux :
| La façon | Ce que vous activez | Qui sert /kz |
|---|---|---|
| Le SDK seul | firstParty: true en Node, FirstParty: true en Go | votre serveur |
| Le Worker seul | KORZEN_FIRST_PARTY = "1" et une route pour /kz/* | votre Cloudflare Worker |
| Le Worker et le SDK | les deux, avec le même chemin | le Worker ; votre serveur lui envoie les visiteurs défiés |
Dans tous les cas, la page charge le tag depuis votre chemin au lieu de l'hôte de Korzen. Le tag prend son adresse de son propre src, donc chaque requête qu'il fait va elle aussi vers /kz :
<script src="/kz/tag.js" data-site-key="YOUR_SITE_KEY" async></script>
Le mode existe dans chaque SDK : Node (et son Worker), Go, Python, PHP, Java et .NET, chacun avec son option dans son README. Un client écrit d'après un guide de framework n'a pas de forwarder : utilisez alors le SDK ou, derrière Cloudflare, le Worker seul, qui donne le mode à une origine dans n'importe quel langage.
Le SDK seul
Votre serveur sert le chemin. Donnez l'option au middleware qui interroge déjà Bot Protection, et donnez au chemin un handler à lui avec les mêmes options. Le client doit être créé par createClient, avec votre clé API : le forwarder l'envoie à Korzen avec chaque requête.
// 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))
- Ce que vous activez.
firstParty: truesurprotectouwithKorzen(actif seulement quand il vauttrue) ; en Go,Options.FirstParty. Ensuite, lesrcdu tag sur vos pages devient/kz/tag.js. L'adresse du visiteur est lue comme la décision la lit : l'optionip, en GoOptions.IP. - Une adresse que le visiteur ne peut pas écrire. Korzen fait confiance à l'adresse que le forwarder envoie avec votre clé : l'option
ipdoit donc en lire une que le visiteur ne peut pas fixer :ipFrom.vercelsur Vercel seulement,ipFrom.cloudflare(Go :korzen.CloudflareIP) seulement si votre serveur ne reçoit du trafic que de Cloudflare,ipFrom.lastForwardedderrière votre propre load balancer ou nginx. Un en-tête que le visiteur peut écrire laisse un script choisir l'adresse que Korzen juge. - Ce qui change pour le visiteur. Rien qu'il voie. Son navigateur charge le tag et envoie son beacon à votre domaine, donc un visiteur dont le réseau bloque Korzen est jugé avec les preuves du tag et peut faire une action qui exige son token. Les requêtes sous le chemin ne sont jamais jugées et n'atteignent jamais vos handlers ; tout autre chemin est jugé comme avant.
- La page de défi. Un chargement de page défié va vers
/kz/challenge?c=…&r=…sur votre domaine au lieu de celui de Korzen, et votre serveur transmet la page, ses fichiers et son envoi. Le même défi, et le visiteur revient à la page qu'il avait demandée. - Fail-open. Quand Bot Protection est lent, en panne ou injoignable depuis votre serveur, chaque requête sous le chemin répond
503avec un corps vide, et le tag abandonne ce signal ; la page et vos autres routes n'attendent rien. Fail-open - Comment savoir que ça marche.
curl -I https://shop.example/kz/tag.jsrépond200, et le panneau réseau du navigateur montre les requêtes du tag vers votre propre domaine. Comment savoir que ça marche
Le Worker seul
Votre Cloudflare Worker sert le chemin, sans changement sur votre serveur, pour une origine dans n'importe quel langage. Mettez en place le Worker comme le montre Cloudflare Workers, puis activez le mode et ajoutez une route pour le chemin :
# 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
- Ce que vous activez.
KORZEN_FIRST_PARTYà1outrue(toute autre valeur que0oufalsele laisse désactivé, avec un avertissement dans le log du Worker), une route pourshop.example/kz/*, et lesrcdu tag sur vos pages en/kz/tag.js. L'adresse du visiteur estCF-Connecting-IP, que Cloudflare définit. - Ce qui change pour le visiteur. Rien qu'il voie. Le tag et son beacon vont vers votre domaine, servis à l'edge de Cloudflare ; votre origine ne voit jamais ces requêtes. Les routes du Worker sont jugées comme avant.
- La page de défi. Un chargement de page que le Worker défie va vers
/kz/challengesur votre domaine, que le Worker sert. - Fail-open. Comme pour le SDK : un
503avec un corps vide pour cette requête seule, et toutes les autres continuent vers votre origine. Fail-open - Comment savoir que ça marche. Comme ci-dessous ; et
npx wrangler tailliste les requêtes sous/kz, tandis que le log d'accès de votre origine n'en montre aucune. Comment savoir que ça marche
Le Worker et le SDK
Quand un Worker est devant votre site et que le SDK tourne dans votre application (pour le context que seule votre application connaît), activez le mode dans les deux, avec le même chemin.
- Ce que vous activez. Le Worker comme ci-dessus, avec sa route pour
/kz/*, etfirstParty: true(Go :FirstParty: true) sur le SDK derrière lui. Le Worker répond lui-même à/kz/*, donc le SDK ne voit jamais ces requêtes. - Ce qui change pour le visiteur. La même chose qu'avec le Worker seul : le tag, son beacon et la page de défi viennent de votre domaine, servis à l'edge.
- La page de défi. Le
firstPartydu SDK envoie les visiteurs qu'il défie vers/kz/challengeau lieu de l'hôte de Korzen, et le Worker sert cette page. Sans lui, un visiteur que le SDK défie va vers l'hôte de Korzen, que son réseau peut bloquer. - Fail-open. Celui qui sert le chemin abandonne de lui-même et répond
503; aucun ne retient l'autre. Si les routes du Worker laissent/kz/*de côté, ou si le Worker est retiré, le SDK sert le chemin lui-même : derrière Cloudflare, donnez-lui alorsip: ipFrom.cloudflare(Go :korzen.CloudflareIP). - Comment savoir que ça marche. Comme ci-dessous ;
npx wrangler tailliste les requêtes sous/kz, et le log de votre serveur n'en montre aucune.
Ce que le chemin sert
Le forwarder, le SDK ou le Worker, répond à celles-ci et à rien d'autre :
| Sur votre domaine | Ce que c'est |
|---|---|
GET /kz/tag.js | le tag, avec les en-têtes de cache de Korzen |
GET /kz/n, POST /kz/s | le nonce du tag et son beacon (un corps de 64 Kio au plus) |
GET /kz/ping | répondu 204 par le forwarder lui-même, jamais transmis |
GET et POST /kz/challenge, GET /kz/challenge/wait | la page de défi et son envoi (16 Kio au plus) |
GET /kz/static/… | le script, le style et les polices de la page de défi |
Tout autre chemin sous /kz est un 404, et un chemin connu avec une autre méthode un 405 ; aucun n'atteint Bot Protection, donc le chemin n'est jamais un proxy ouvert. À Korzen, le forwarder envoie les en-têtes du navigateur d'une courte liste (User-Agent, Accept, Accept-Language, Content-Type, Origin, Sec-Fetch-*, les client hints, If-None-Match), votre clé API comme bearer et l'adresse du visiteur. Jamais un cookie, l'Authorization du navigateur ni un X-Forwarded-*. Ce qui revient garde les en-têtes de cache et de sécurité de Korzen, jamais un Set-Cookie.
Korzen n'accepte l'adresse du visiteur que d'une requête sur ces routes qui porte votre clé API, et sur le beacon que pour votre propre site key ; tout le reste est refusé en 403. Votre clé n'atteint jamais le navigateur.
Le cookie _kz du tag et son stockage restent sur votre domaine, comme avant ; les données que Korzen reçoit sont les mêmes. Quelques preuves que Korzen ne lit que quand le navigateur se connecte directement à Korzen manquent à travers un forwarder ; le reste des preuves du tag arrive, et rien de ce qui manque ne compte contre un visiteur.
Un autre chemin
firstPartyPath (Go : Options.FirstPartyPath ; le Worker : KORZEN_FIRST_PARTY_PATH) nomme un autre chemin, par exemple quand une liste de blocage apprend /kz. Il commence par /, finit sans, et compte au plus 64 caractères en segments de A-Z a-z 0-9 . _ ~ -. Un chemin illisible est consigné une fois dans le log, et le mode reste désactivé. Utilisez le même chemin dans le src du tag, dans le SDK et dans le Worker.
Fail-open
Le chemin ne retient jamais votre page ni vos autres routes :
- Chaque requête transmise abandonne d'elle-même : après 1 s pour un
GET, 2,5 s pour unPOST. Un timeout, une erreur réseau, une réponse de plus de 4 Mio ou une panne du forwarder donne un503avec un corps vide etCache-Control: no-store; les redirections ne sont pas suivies. Les4xxet5xxde Bot Protection lui-même passent tels quels. - Sans l'adresse du visiteur (l'option
ipn'en lit aucune), le nonce, le beacon et le défi répondent503; le tag et les fichiers de la page de défi sont toujours servis. - Le tag abandonne alors ce signal, comme quand l'hôte de Korzen est en panne. Un tag qui n'a rien envoyé n'est jamais une preuve de bot : le visiteur est jugé sur ce que votre serveur envoie.
Comment savoir que ça marche
curl -I https://shop.example/kz/tag.jsrépond200, etcurl -I https://shop.example/kz/pingrépond204.- Dans les outils de développement du navigateur, sur une page avec le tag, le panneau réseau montre
/kz/tag.js,/kz/n,/kz/pinget/kz/ssur votre propre domaine, répondus200ou204, et aucune requête vers l'hôte de Korzen. - Passez par une action protégée, puis cliquez sur Vérifier votre intégration sur la page Configuration : Le token du tag dans cet appel indique Vu. Vos décisions apparaissent comme avant sur la page Décisions du tableau de bord.
- Avec une
Content-Security-Policy, l'hôte de Korzen peut en sortir :script-src 'self'; connect-src 'self'; worker-src blob:suffit pour le tag. Le tag
Erreurs fréquentes
- Le tag encore chargé depuis l'hôte de Korzen : le mode sert le chemin, mais seul le
srcdu tag y envoie le navigateur. - Un body parser avant le forwarder dans Express : le corps du beacon est lu avant que le forwarder le reçoive. Montez-le avant tout parser, ou sur le chemin seul.
- Le Worker avec
KORZEN_FIRST_PARTYmais sans route pour/kz/*: les requêtes atteignent votre origine, qui répond404sauf si le SDK y sert le chemin. - Deux chemins : le Worker sur l'un et le SDK sur un autre. Le SDK envoie alors les visiteurs défiés vers un chemin que le Worker ne sert pas.
- Appeler
/v1/decideà la main : sonchallenge.urlest toujours l'hôte de Korzen. Seuls les SDK et le Worker envoient le visiteur vers votre chemin.