एक हस्ताक्षरित request क्या साबित करती है?
अधिकांश स्वचालित traffic अपने आप को user agent string से पहचानता है. वह string एक दावा है, और उसे कॉपी करने की लागत कुछ नहीं होती. हस्ताक्षरित requests इस स्थिति को बदलती हैं. जब एक स्वचालित client अपने HTTP requests को private key से sign करता है और matching public key को operator से जुड़े स्थान पर प्रकाशित करता है, तो आपका server यह जांच सकता है कि request वास्तव में उसी key को रखने वाले व्यक्ति द्वारा बनाई गई थी.
इसके पीछे का मानक HTTP Message Signatures है, जो RFC 9421 के रूप में प्रकाशित है. IETF Web Bot Auth working group स्वचालित clients के लिए conventions के साथ इस पर काम करता है: एक agent अपनी key directory की ओर कैसे संकेत करता है और उसे request के किन components पर हस्ताक्षर करना चाहिए. November 2026 तक, working group का protocol document draft-ietf-webbotauth-httpsig-protocol है, जो Signature-Agent header, JSON Web Key Sets पर आधारित एक key directory format और उसे serve करने के लिए एक well-known URI परिभाषित करता है. दोनों को विस्तार से समझना उपयोगी है, क्योंकि verification में सूक्ष्म गलतियां आसानी से हो सकती हैं.
Mechanics से पहले, परिणाम को ठीक से समझें. एक मान्य signature दिखाता है कि request पर किसी प्रकाशित identifier, जैसे operator के domain, से जुड़ी key ने हस्ताक्षर किए थे, और request के signed हिस्से बदले नहीं गए थे. यह नहीं दिखाता कि agent को किसने निर्देश दिया, क्या किसी व्यक्ति ने उसे authority सौंपी, या action सुरक्षित है या नहीं. identity evidence और authorization अलग प्रश्न हैं, और आपका application दूसरे का उत्तर देता है. हमारे ब्लॉग पोस्ट signed AI agent requests क्या साबित करते हैं में उदाहरणों के साथ इस सीमा को समझाया गया है.
शामिल headers
एक हस्ताक्षरित request में आम तौर पर तीन headers होते हैं:
Signature-Input(RFC 9421, Section 4.1) हर signature का वर्णन करता है: एक label, covered components की सूची, औरcreated,expires,keyid,alg,nonceऔरtagजैसे parameters.Signature(RFC 9421, Section 4.2) हर label के लिए signature bytes को structured field के रूप में, base64 encoded, रखता है.Signature-Agent(Web Bot Auth conventions से) यह बताता है कि client's public keys कहां प्रकाशित हैं, आम तौर पर operator के domain पर एक HTTPS URL.
एक सरलीकृत उदाहरण:
GET /api/catalog?page=2 HTTP/1.1
Host: shop.example
Signature-Agent: "https://agent.example"
Signature-Input: sig1=("@method" "@authority" "@path" "signature-agent");created=1762934400;expires=1762934700;keyid="kq1";alg="ed25519";tag="web-bot-auth";nonce="d9f1c2"
Signature: sig1=:Base64SignatureBytes==:यह उदाहरण पठनीयता के लिए सरलीकृत है. current working group draft में, Signature-Agent स्वयं signature label द्वारा keyed एक structured field है (उदाहरण के लिए sig1="https://agent.example"), इसलिए जांचें कि आपकी verification library किस रूप की अपेक्षा करती है.
चरण 1: structured fields को सही ढंग से parse करें
Signature-Input और Signature HTTP Structured Fields हैं (RFC 9651, जो RFC 8941 को अप्रचलित करता है). इन्हें string splitting से parse न करें. quoted strings, parameters और inner lists सभी की grammar सटीक होती है, और sloppy parser false rejections और वास्तविक security gaps दोनों पैदा करता है.
एक maintained structured-field parser का उपयोग करें, या उससे भी बेहतर, एक maintained RFC 9421 library का जो parsing और verification दोनों को साथ संभालती है. specification को शून्य से implement करना सीखने के लिए अच्छा अभ्यास है और production के लिए खराब विकल्प. नीचे दिए गए चरण बताते हैं कि ऐसी library क्या करती है, ताकि आप उसे सही ढंग से configure कर सकें और उसके output की समीक्षा कर सकें.
चरण 2: किस signature का मूल्यांकन करना है, चुनें
एक request में एक से अधिक signature label हो सकते हैं. अपनी policy से मेल खाने वाले label को चुनें, उदाहरण के लिए वह label जिसका tag web-bot-auth है. यदि:
- किसी signature में आपके आवश्यक parameters नहीं हैं,
- algorithm आपकी allowlist पर नहीं है (उदाहरण के लिए
ed25519), या - covered components में आपके द्वारा आवश्यक न्यूनतम set शामिल नहीं है,
तो verification purposes के लिए request को अस्वीकार करें (serving purposes के लिए नहीं).
स्वचालित clients के लिए एक उचित न्यूनतम @method, @authority और @path है, साथ ही जब वह header मौजूद हो तब signature-agent भी. @authority के बिना, एक site के लिए capture किया गया signature दूसरी site के विरुद्ध replay किया जा सकता है. @path के बिना, इसे endpoints के across दोबारा उपयोग किया जा सकता है. Web Bot Auth protocol draft agents से @authority या @target-uri को cover करने की अपेक्षा करता है, और चेतावनी देता है कि केवल authority को cover करने वाला signature expiry तक उस host पर किसी भी method या path के विरुद्ध verify होता है.
चरण 3: time parameters जांचें
RFC 9421, Section 2.3 में परिभाषित time parameters created और expires पढ़ें. फिर:
- उन signatures को अस्वीकार करें जिनका
createdtime, छोटी clock skew allowance से आगे future में है. - उन signatures को अस्वीकार करें जो
expiresपार कर चुके हैं. - यदि
expiresअनुपस्थित है, तोcreatedके आधार पर अपनी अधिकतम आयु लागू करें.
छोटी validity windows इस बात को सीमित करती हैं कि captured request को कितनी देर तक replay किया जा सकता है.
चरण 4: key खोजें
Signature-Agent header operator की key directory की ओर संकेत करता है. इसे HTTPS पर प्राप्त करें, और केवल HTTPS पर. Web Bot Auth protocol draft directory को JSON Web Key Set के रूप में वर्णित करता है (keys JWK format में) जो उस origin पर http-message-signatures-directory well-known URI से serve की जाती है. फिर वह key खोजें जिसका identifier keyid parameter से मेल खाता हो.
type Jwk = { kid: string; kty: string; crv?: string; x?: string };
const keyCache = new Map<string, { keys: Jwk[]; fetchedAt: number }>();
const KEY_TTL_MS = 60 * 60 * 1000;
export async function getKey(directoryUrl: string, keyId: string): Promise<Jwk | null> {
const url = new URL(directoryUrl);
if (url.protocol !== "https:") return null;
const cached = keyCache.get(url.origin);
const fresh = cached && Date.now() - cached.fetchedAt < KEY_TTL_MS;
const keys = fresh ? cached.keys : await fetchKeys(url.origin);
return keys.find((k) => k.kid === keyId) ?? null;
}
async function fetchKeys(origin: string): Promise<Jwk[]> {
const res = await fetch(`${origin}/.well-known/http-message-signatures-directory`, {
headers: { accept: "application/http-message-signatures-directory+json, application/json" },
signal: AbortSignal.timeout(2000),
});
if (!res.ok) return [];
const body = (await res.json()) as { keys?: Jwk[] };
const keys = Array.isArray(body.keys) ? body.keys : [];
keyCache.set(origin, { keys, fetchedAt: Date.now() });
return keys;
}key discovery के लिए व्यावहारिक नियम:
- Keys cache करें bounded lifetime के साथ ताकि verification हर request पर network call न जोड़े.
- Short timeout सेट करें और failed fetch को "could not verify" मानें, कभी भी "verified" नहीं.
- जिन origins से आप fetch करते हैं उन्हें सीमित करें यदि संभव हो, या कम से कम private address ranges को block करें ताकि server-side request forgery से बचा जा सके. protocol draft security considerations में इसी कारण server-side request forgery का उल्लेख करता है.
- Identity को origin से जोड़ें, user agent में दिए गए free-text नाम से नहीं. जो identifier आप record करते हैं, वह directory origin है.
चरण 5: signature base को फिर से बनाएं
Signer ने raw request पर हस्ताक्षर नहीं किए थे. उसने signature base नाम की एक canonical string पर हस्ताक्षर किए थे (RFC 9421, Section 2.5), जो क्रम में covered components से, और उसके बाद @signature-params line से बनाई गई होती है. आपका verifier प्राप्त request से वही string फिर से बनाता है.
ऊपर दिए गए उदाहरण के लिए base इस प्रकार दिखता है:
"@method": GET
"@authority": shop.example
"@path": /api/catalog
"signature-agent": "https://agent.example"
"@signature-params": ("@method" "@authority" "@path" "signature-agent");created=1762934400;expires=1762934700;keyid="kq1";alg="ed25519";tag="web-bot-auth";nonce="d9f1c2"उन विवरणों पर नज़र रखें जो proxies के पीछे verification को तोड़ते हैं:
@authorityवह host होना चाहिए जिसे client ने target किया था. यदि load balancerHostको rewrite करता है, तो वह मूल value उपयोग करें जिसे वह forward करता है.@pathquery string को exclude करता है. यदि client ने@queryको cover किया था, तो उसे ठीक वैसे ही पुनर्निर्मित करें जैसा प्राप्त हुआ था.- Header values को निर्दिष्ट तरीके से canonicalize किया जाता है: trimmed, और multiple values को combined किया जाता है. एक अच्छी library यह आपके लिए करती है.
चरण 6: signature सत्यापित करें
Base और public key के साथ, verification RFC 9421, Section 3.2 के steps का पालन करते हुए एक single call है. Node.js में Ed25519 के लिए, built-in crypto module का उपयोग करते हुए:
import { createPublicKey, verify } from "node:crypto";
export function verifyEd25519(jwk: Jwk, base: string, signatureB64: string): boolean {
const key = createPublicKey({ key: jwk as any, format: "jwk" });
return verify(null, Buffer.from(base, "utf8"), key, Buffer.from(signatureB64, "base64"));
}यदि check fail होता है, तो request verified नहीं है. फिर भी इसे serve किया जा सकता है. बस उसे "verified" basis नहीं मिलता.
चरण 7: replay रोकें
एक मान्य signature को capture करके expiry तक दोबारा भेजा जा सकता है. RFC 9421, Section 7.2.2 signature replay को कवर करता है, और Web Bot Auth protocol draft अपने nonce नियम जोड़ने के बजाय उसी पर निर्भर करता है. दो controls उस window के अधिकांश हिस्से को बंद कर देते हैं:
- Short expiry, चरण 3 में लागू की गई.
- Nonce tracking. जब
nonceमौजूद हो, तो उसे उसके key identifier के साथ expiry तक किसी shared store में रखें, और दूसरी बार उपयोग को अस्वीकार करें.
const seen = new Map<string, number>();
export function acceptNonce(keyId: string, nonce: string, expiresAt: number): boolean {
const id = `${keyId}:${nonce}`;
const now = Date.now() / 1000;
for (const [k, exp] of seen) if (exp < now) seen.delete(k);
if (seen.has(id)) return false;
seen.set(id, expiresAt);
return true;
}multi-instance deployment में, nonces को Redis जैसे shared store में रखें, जिसकी time to live remaining validity के बराबर हो.
चरण 8: basis के साथ परिणाम दर्ज करें
Verification evidence पैदा करती है, verdict नहीं. इसे ऐसे रूप में record करें जिसे आपकी analytics और policies उपयोग कर सकें:
const result = {
actor: "agent",
basis: "verified",
operator: "https://agent.example",
keyId: "kq1",
coveredComponents: ["@method", "@authority", "@path", "signature-agent"],
verifiedAt: new Date().toISOString(),
};जब verification fail हो या चल ही न सके, तो कारण भी record करें: missing headers, unsupported algorithm, key not found, expired, replayed, या signature mismatch. ये कारण मूल्यवान हैं. किसी एक operator से "key not found" में अचानक वृद्धि अक्सर इस बात का संकेत है कि उन्होंने keys rotate की हैं, न कि वे आप पर हमला कर रहे हैं.
signature verification से आपको क्या log करना चाहिए?
operator origin, key identifier, covered components, time parameters, outcome और failure reason log करें. पूरे signature bytes या पूरे request bodies log न करें. logs को इतना समय रखें कि आप patterns का अध्ययन कर सकें, और इतना कम कि आपकी privacy commitments का सम्मान हो.
एक verified signature आपकी policy को कैसे बदलनी चाहिए?
एक बार requests verify होने लगें, तो आप उन्हें अर्थपूर्ण तरीके से अलग तरह से संभाल सकते हैं. humans और AI agents के लिए app policies डिजाइन करने पर हमारी पोस्ट designing app policies for humans and AI agents व्यापक policy model को कवर करती है:
- verified operators को read-only routes पर unverified automation की तुलना में higher rate limit के साथ अनुमति दें.
- उन्हें structured responses दें, जैसे JSON या Markdown, full HTML pages के बजाय.
- high-impact actions को अपनी सामान्य authorization के पीछे रखें. एक verified signature आपको बताता है कि कौन सा client call कर रहा है, यह नहीं कि वह account बदल सकता है.
Observation mode में शुरू करें. यह मापें कि आपके automated traffic का कितना हिस्सा signed है, कौन से operators दिखाई देते हैं, और verification कितनी बार fail होती है, इससे पहले कि कोई policy उस पर निर्भर करे.
Proof of Actor यहां कैसे फिट होता है
Signature verification कई sources of evidence में से एक है. Proof of Actor इसे अन्य signals के साथ जोड़ता है और हर result पर basis को visible रखता है, ताकि एक verified agent को कभी उस agent के साथ भ्रमित न किया जाए जिसने केवल अपने आप को declared किया था. आपका application तय करता है कि आगे क्या होता है.
इसे हमारे engineers के साथ production app में बनाने के लिए, early access के लिए apply करें. evidence क्या दिखा सकता है और क्या नहीं, इसकी पूरी तस्वीर के लिए Detection & Limitations पढ़ें.
स्रोत
- RFC 9421: HTTP Message Signatures: signing और verification का standard, जिसमें signature parameters, signature base और replay considerations शामिल हैं
- RFC 9651: Structured Field Values for HTTP: grammar जिसका उपयोग
Signature-InputऔरSignatureकरते हैं - IETF Web Bot Auth working group: automated client authentication work का charter और status
- draft-ietf-webbotauth-httpsig-protocol: Internet-Draft जो
Signature-Agent, JWKS key directory और उसकी well-known URI परिभाषित करता है (November 2026 तक work in progress) - RFC 7517: JSON Web Key (JWK): published key directories में उपयोग होने वाला key format
- RFC 8615: Well-Known URIs: key directory जैसे well-known paths कैसे register किए जाते हैं
- RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA): example में उपयोग किया गया Ed25519 algorithm
- Node.js crypto documentation: चरण 6 में उपयोग किए गए
createPublicKeyऔरverify