Rules-এর বদলে actor context দিয়ে শুরু করবেন কেন?
যে দলগুলো তাদের traffic-এ AI agent লক্ষ্য করে, তারা প্রায়ই আগে rule প্রয়োগ করতে চায়। user agent block করা, challenge যোগ করা, rate limit কড়া করা। সমস্যা হলো, traffic বোঝার আগে লেখা rule প্রায়ই ভুল লোককে আঘাত করে। বৈধ assistant block হয়ে যায়, আসল user challenge পায়, আর যে automation নিয়ে আপনি সত্যিই চিন্তিত, সেটি তবু চলতেই থাকে কারণ শুরুতেই সে নিজেকে চিহ্নিত করেনি।
Actor context হলো rules-এর আগের ধাপ। প্রতিটি request-এর জন্য আপনি record করেন আপনার application কী observe করতে পারে, কে বা কী কাজ করছে তা নিয়ে: একজন interactive মানুষ, AI assistant-এর সাথে কাজ করা একজন মানুষ, একটি autonomous agent, অথবা এমন কিছু যাকে এখনও আলাদা করে বোঝা যাচ্ছে না। আপনি এই দৃষ্টিভঙ্গির পেছনের evidence record করেন, এবং তা request outcome-এর পাশে রাখেন। এক বা দুই সপ্তাহ এভাবে চলার পর আপনার হাতে এমন কিছু আসে যা কোনো rule template দিতে পারে না: আপনার নিজস্ব traffic-এর মানচিত্র। যদি আপনি এখনও সিদ্ধান্ত নিচ্ছেন যে agent আসলেই আপনার site-এ পৌঁছাচ্ছে কি না, তাহলে website traffic AI agent থেকে আসছে কি না কীভাবে বুঝবেন দিয়ে শুরু করুন।
এই guide টি plain middleware ব্যবহার করে একটি Node.js application-এ সেই layer তৈরি করে। এটি Express-এর সাথে কাজ করে, এবং একই ধারণা Fastify, Koa, Hono বা Next.js route handler-এও প্রযোজ্য।
আপনি কী তৈরি করবেন
শেষে আপনার হাতে থাকবে:
- প্রতিটি request থেকে actor evidence বের করার একটি middleware।
- প্রতিটি result-এর জন্য stated basis সহ একটি ছোট, explicit classification।
- Structured observation log, যা request কীভাবে handle হবে তা কখনোই বদলাবে না।
- result-টি request-এর সাথে attach করার একটি উপায়, যাতে পরবর্তী handler-গুলো তা read করতে পারে।
এখানে কিছুই request block করে না। সেটাই ইচ্ছাকৃত।
ধাপ 1: আপনার server আসলে কী evidence দেখতে পারে?
একটি server মানুষ যতটা ভাবে, তার চেয়ে কম কিছু দেখে। code লেখার আগে আপনার edge-এ উপলব্ধ signal-গুলো তালিকাভুক্ত করুন:
- Request signature. কিছু automated client HTTP Message Signatures ব্যবহার করে request sign করে (RFC 9421),
Signature-InputএবংSignatureheader পাঠায়, এবং প্রায়ইSignature-Agentheader-এর সাথেও আসে, যা operator-এর প্রকাশিত key-এর দিকে ইঙ্গিত করে, যেমন IETF Web Bot Auth protocol draft-এ বর্ণিত। - Declared identity. Client-রা নিজেদের নাম দিতে পারে
User-Agentheader-এ,Fromheader-এ, অথবা protocol metadata-র মাধ্যমে, যেমন একটি MCP client name। MCP client-রা 2025-11-25 revision-এর initialize request-এ একটি self-chosenclientInfoname report করে, এবং 2026-07-28 revision client identity-কে per-request metadata হিসেবে বহন করে। এগুলো ঘোষণা, এবং যে কেউ সেগুলো নকল করতে পারে। - Authentication context. Request-এ session cookie, bearer token বা API key আছে কি না, এবং credential-টি কী ধরনের।
- Protocol shape. Accept header, client HTML নাকি JSON request করছে, এটি page asset লোড করছে কি না, এবং redirect ও cookie কীভাবে handle করছে।
- Application declaration. আপনার নিজস্ব product এমন কিছু জানে যা network পারে না, যেমন user-এর "AI assisted" option বেছে নেওয়া, বা আপনার built-in assistant feature থেকে আসা request।
প্রতিটি signal-এর শক্তি আলাদা। একটি validated signature যাচাইযোগ্য। একটি user agent string একটি দাবি। একটি missing cookie শুধু missing। এগুলো আলাদা রাখা-ই এই exercise-এর মূল উদ্দেশ্য।
ধাপ 2: ফলাফলটি স্পষ্টভাবে model করুন
Detection logic লেখার আগে actor result-এর shape নির্ধারণ করুন। একটি ছোট, typed model সবাইকে স্পষ্ট রাখে যে একটি classification-এর মানে কী। এখানে ব্যবহৃত চারটি class Human, AI-assisted or agent: a practical taxonomy for application traffic-এ ব্যাখ্যা করা হয়েছে।
export type ActorClass = "human" | "human_ai" | "agent" | "unknown";
export type EvidenceBasis = "verified" | "declared" | "inferred" | "unknown";
export interface ActorEvidence {
signaturePresent: boolean;
signatureAgent?: string;
declaredClient?: string;
credentialType: "session" | "api_key" | "bearer" | "none";
acceptsHtml: boolean;
appDeclaredAssist: boolean;
}
export interface ActorResult {
actor: ActorClass;
basis: EvidenceBasis;
reasons: string[];
evidence: ActorEvidence;
observedAt: string;
}দুটি field সবচেয়ে গুরুত্বপূর্ণ। actor হলো class। basis বলে আপনি কেন তা বিশ্বাস করছেন। validated signature-এর ভিত্তিতে পাওয়া agent result এবং user agent string-এর ভিত্তিতে পাওয়া agent result দুটোই "agent", কিন্তু পরে treatment-এর ক্ষেত্রে তাদের মধ্যে বড় পার্থক্য আছে, তাই কখনোই সেগুলো এক করে দেখবেন না।
ধাপ 3: middleware-এ evidence বের করুন
Extraction ধাপ headers এবং request state পড়ে। এটি এখনই কিছু নির্ধারণ করে না।
import type { Request, Response, NextFunction } from "express";
const KNOWN_AGENT_TOKENS = ["bot", "crawler", "spider", "agent", "gpt", "claude"];
export function extractEvidence(req: Request): ActorEvidence {
const ua = (req.get("user-agent") || "").toLowerCase();
const auth = req.get("authorization") || "";
const hasSession = Boolean(req.cookies?.session);
let credentialType: ActorEvidence["credentialType"] = "none";
if (hasSession) credentialType = "session";
else if (auth.toLowerCase().startsWith("bearer ")) credentialType = "bearer";
else if (req.get("x-api-key")) credentialType = "api_key";
const declaredToken = KNOWN_AGENT_TOKENS.find((t) => ua.includes(t));
return {
signaturePresent: Boolean(req.get("signature") && req.get("signature-input")),
signatureAgent: req.get("signature-agent") || undefined,
declaredClient: declaredToken ? ua.slice(0, 200) : undefined,
credentialType,
acceptsHtml: (req.get("accept") || "").includes("text/html"),
appDeclaredAssist: req.get("x-app-assist") === "1",
};
}এই code সম্পর্কে কয়েকটি কথা:
signaturePresentশুধু record করে যে signature header আছে। Validation একটি আলাদা ধাপ, যা signed agent request verify করার guide-এ covered।- user agent token list ইচ্ছাকৃতভাবে সহজ। এটি declaration তৈরি করে, কখনোই verification নয়।
x-app-assistআপনার frontend থেকে user যখন built-in AI feature-এর মাধ্যমে কাজ করে, তখন যা পাঠায় তার placeholder। আপনার আসল mechanism দিয়ে এটি replace করুন।
ধাপ 4: stated basis সহ classify করুন
এখন evidence-কে result-এ রূপান্তর করুন। rule-গুলো ছোট রাখুন, strongest evidence থেকে weakest-এর দিকে ordered রাখুন, এবং সবসময় Unknown-এ fall through করুন।
export async function classify(
evidence: ActorEvidence,
verifySignature: () => Promise<boolean>,
): Promise<ActorResult> {
const reasons: string[] = [];
const observedAt = new Date().toISOString();
if (evidence.signaturePresent && (await verifySignature())) {
reasons.push("request signature validated");
return { actor: "agent", basis: "verified", reasons, evidence, observedAt };
}
if (evidence.appDeclaredAssist) {
reasons.push("application reported its built-in assistant");
return { actor: "human_ai", basis: "declared", reasons, evidence, observedAt };
}
if (evidence.declaredClient) {
reasons.push("client declared itself as automated");
return { actor: "agent", basis: "declared", reasons, evidence, observedAt };
}
if (evidence.credentialType === "session" && evidence.acceptsHtml) {
reasons.push("interactive browser session");
return { actor: "human", basis: "inferred", reasons, evidence, observedAt };
}
reasons.push("insufficient evidence");
return { actor: "unknown", basis: "unknown", reasons, evidence, observedAt };
}লক্ষ করুন, এটি কী করে না। এটি কখনোই declaration-কে verification-এ upgrade করে না। এটি কখনোই এমন request-কে Human assign করে না যার কোনো interactive signal নেই। যখন এটি বুঝতে পারে না, তখন এটি Unknown বলে। Unknown একটি বৈধ, দরকারী উত্তর, এবং এটি আপনাকে স্পষ্টভাবে বলে দেয় visibility কোথায় শেষ। AI traffic-এর জন্য কেন Unknown একটি বৈধ result, তার পূর্ণ ব্যাখ্যা আমরা Unknown কেন AI traffic-এর জন্য একটি বৈধ result-এ দিই।
ধাপ 5: observation mode-এ এটি wire করুন
Middleware প্রথমেই mount করুন, result request-এর সাথে attach করুন, এবং log করুন। এর ভিত্তিতে branch করবেন না।
import express from "express";
import cookieParser from "cookie-parser";
const app = express();
app.use(cookieParser());
app.use(async (req, res, next) => {
try {
const evidence = extractEvidence(req);
const result = await classify(evidence, async () => false);
res.locals.actor = result;
res.on("finish", () => {
logActor({
route: req.route?.path ?? req.path,
method: req.method,
status: res.statusCode,
actor: result.actor,
basis: result.basis,
reasons: result.reasons,
});
});
} catch {
res.locals.actor = undefined;
}
next();
});তিনটি বিষয় এটিকে নিরাপদ করে:
tryblock নিশ্চিত করে যে detection-এর failure কখনোই response-কে প্রভাবিত করে না। Observation অবশ্যই fail open হতে হবে।- Logging
finish-এ ঘটে, তাই আপনি আসল status code capture করেন এবং পরে classification-এর সাথে outcome তুলনা করতে পারেন। - আপনি real validation implement না করা পর্যন্ত
verifySignature-কেfalse-এ stub করা হয়। এতে signed request-গুলো declared বা unknown bucket-এ থাকে, অতিরঞ্জিত হয় না।
ধাপ 6: শুধু debugging নয়, analysis-এর জন্য log করুন
এমন log লিখুন যা আপনি aggregate করতে পারেন। প্রতি request-এ একটি structured line-ই যথেষ্ট।
function logActor(entry: Record<string, unknown>) {
process.stdout.write(JSON.stringify({ type: "actor_observation", ...entry }) + "\n");
}এই log থেকে personal data দূরে রাখুন। আপনার route, class, basis, reason এবং outcome দরকার। আপনার traffic mix বুঝতে full IP address, raw cookie বা request body দরকার নেই। correlation-এর জন্য যদি কোনো identifier রাখতেই হয়, তাহলে rotating salt দিয়ে hash করুন এবং retention period ছোট রাখুন।
ধাপ 7: action নেওয়ার আগে data পড়ুন
সাধারণ weekly pattern দেখতে যথেষ্ট সময় observation mode-এ চালান। তারপর কয়েকটি প্রশ্নের উত্তর দিন:
- কোন route-গুলো agent আকর্ষণ করে? সাধারণত documentation, catalog এবং search endpoint-গুলো তা করে। account এবং checkout flow সাধারণত তা করা উচিত নয়।
- Agent result-এর কত ভাগ verified বনাম declared? আপনি policy লেখার সময় identity-এর উপর কতটা নিরাপদে নির্ভর করতে পারবেন, সেই ratio তা বলে।
- Unknown কোথায় বেশি কেন্দ্রীভূত? কোনো route-এ Unknown rate বেশি হলে প্রায়ই বোঝা যায় সেখানে signal অনুপস্থিত, যেমন এমন একটি page যা আপনার frontend code কখনো চালায় না।
- Outcome কি class অনুযায়ী আলাদা? Error rate, conversion step বা abuse report class ধরে তুলনা করুন। এখান থেকেই আসল policy-এর ধারণা আসে।
উত্তরগুলো প্রায়ই অবাক করবে। দলগুলো নিয়মিত দেখতে পায় যে তাদের "bot problem"-এর বড় অংশ আসলে বৈধ automation, যা structured endpoint থাকলে সহজেই ব্যবহার করত।
ধাপ 8: result-টি আপনার app-এর বাকি অংশে expose করুন
একবার data প্রবাহিত হতে শুরু করলে, non-enforcing use-এর জন্য handler-গুলোকে res.locals.actor পড়তে দিন: analytics tag, response format বেছে নেওয়া, বা support ticket যে একটি AI-assisted session থেকে এসেছে তা record করা। এই ব্যবহারগুলো কাউকে lock out করার ঝুঁকি ছাড়াই experience উন্নত করে।
app.get("/docs/:page", (req, res) => {
const actor = res.locals.actor as ActorResult | undefined;
if (actor?.actor === "agent" && req.accepts("text/markdown")) {
return res.type("text/markdown").send(renderMarkdown(req.params.page));
}
return res.render("doc", { page: req.params.page });
});Challenge, rate limit বা step-up check-এর মতো enforcement পরে আসে, false positive কতটা হয়েছে তা মাপার পর। actor-aware policy roll out করার guide-এ সেই process covered।
কোন ভুলগুলো এড়ানো উচিত?
- User agent-কে identity হিসেবে ধরা। এটি বদলানো সবচেয়ে সহজ header। এটিকে declaration হিসেবে record করুন। এমনকি AI operator-রাও তা বলে: Anthropic-এর তার hosted browser agent কীভাবে নিজেকে identify করে তার guidance-এ বলা আছে যে যে কেউ একই User-Agent header পাঠাতে পারে, এবং traffic-কে genuine হিসেবে ধরার আগে তাদের প্রকাশিত IP address check করতে বলা হয়েছে।
- Default হিসেবে Human ধরা। যখনই আপনার code bot signal খুঁজে পায় না তখন যদি Human বলে, তাহলে আপনার Human সংখ্যা ফুলে উঠবে এবং আপনার policy ভুল traffic-এর উপর ভরসা করবে।
- Class এবং basis মিশিয়ে ফেলা। সবসময় দুটোই store করুন। শুধু "Agent" দেখানো একটি dashboard verified operator এবং copied string-এর পার্থক্য আড়াল করে।
- Observation চলাকালীন block করা। সাময়িক block-ও আপনার measurement invalid করে, কারণ blocked client-রা তাদের আচরণ বদলে ফেলে।
Proof of Actor এখানে কোথায় fit করে
উপরের middleware একটি solid starting point, এবং এটি core model দেখায়: আগে evidence, প্রতিটি result-এর জন্য explicit basis, Unknown দৃশ্যমান রাখা, এবং সিদ্ধান্ত আপনার application-এর হাতে ছেড়ে দেওয়া। Proof of Actor একই model-এর উপর build করে, server, edge, browser এবং MCP context জুড়ে আরও গভীর signal coverage এবং analytics সহ, যা আপনাকে আত্মবিশ্বাসের সাথে Detect, Understand এবং Route করতে সাহায্য করে।
আপনি যদি production app-এ এটি আরও এগিয়ে নিতে সাহায্য চান, early access-এর জন্য আবেদন করুন। সম্পূর্ণ decision flow দেখতে How Proof of Actor works পড়ুন।
Source
- RFC 9421: HTTP Message Signatures: signed request-এর পেছনের standard
- draft-ietf-webbotauth-httpsig-protocol: IETF Web Bot Auth draft, যা
Signature-Agentheader সংজ্ঞায়িত করে (November 2026 অনুযায়ী কাজ চলছে) - RFC 9110: HTTP Semantics, User-Agent and From: self-reported client identification header
- MCP specification 2025-11-25: Lifecycle:
initializerequest এবংclientInfo - MCP specification 2026-07-28: Versioning and Compatibility: per-request version, identity এবং capability metadata
- Anthropic: Anthropic-hosted browser কীভাবে নিজেদের identify করে: user agent token, published IP address এবং header copy করা যায় সেই সতর্কবার্তা