İmzalı bir istek neyi kanıtlar?
Otomatik trafiğin çoğu kendini bir user agent string ile tanımlar. Bu bir iddiadır ve kopyalamak hiçbir maliyet gerektirmez. İmzalı istekler bu durumu değiştirir. Bir otomatik istemci HTTP isteklerini özel bir anahtarla imzalayıp eşleşen açık anahtarı operatörüne bağlı bir konumda yayımladığında, sunucunuz isteğin gerçekten o anahtara sahip biri tarafından üretildiğini denetleyebilir.
Bunun arkasındaki standart, RFC 9421 olarak yayımlanan HTTP Message Signatures'tır. IETF Web Bot Auth çalışma grubu bunun üzerine otomatik istemciler için kurallar inşa eder: bir agent'ın anahtar dizinini nasıl işaret edeceği ve istek bileşenlerinden hangilerini imzalaması gerektiği. Kasım 2026 itibarıyla çalışma grubunun protokol belgesi draft-ietf-webbotauth-httpsig-protocol'dür; bu belge Signature-Agent başlığını, JSON Web Key Sets tabanlı bir anahtar dizini biçimini ve bunu sunmak için bir well-known URI'yi tanımlar. İkisini de ayrıntılı anlamak gerekir, çünkü doğrulamayı küçük ama kritik hatalarla yanlış yapmak kolaydır.
Mekaniğe geçmeden önce sonucu netleştirin. Geçerli bir imza, isteğin operatörün alan adı gibi yayımlanmış bir tanımlayıcıyla ilişkilendirilmiş bir anahtar tarafından imzalandığını ve isteğin imzalanan parçalarının değiştirilmediğini gösterir. Kimin agent'ı yönlendirdiğini, bir kişinin ona yetki devredip devretmediğini veya işlemin güvenli olup olmadığını göstermez. Kimlik kanıtı ve yetkilendirme ayrı sorulardır ve ikinci soruyu uygulamanız yanıtlar. İmzalı AI agent isteklerinin neyi kanıtladığı üzerine blog yazımız bu sınırı örneklerle ele alır.
Hangi başlıklar yer alır?
İmzalı bir istek genellikle üç başlık taşır:
Signature-Input(RFC 9421, Bölüm 4.1) her imzayı tanımlar: bir etiket, kapsanan bileşenlerin listesi vecreated,expires,keyid,alg,noncevetaggibi parametreler.Signature(RFC 9421, Bölüm 4.2) her etiket için imza baytlarını structured field olarak, base64 kodlu biçimde taşır.Signature-Agent(Web Bot Auth kurallarından) istemcinin açık anahtarlarının yayımlandığı yeri gösterir, genellikle operatörün alan adında bir HTTPS URL'si.
Basitleştirilmiş bir örnek:
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==:Örnek, okunabilirlik için sadeleştirilmiştir. Geçerli çalışma grubu taslağında Signature-Agent başlığın etiketine göre anahtarlanmış bir structured field'dır (örneğin sig1="https://agent.example"), bu yüzden doğrulama kütüphanenizin hangi biçimi beklediğini kontrol edin.
1. Adım: Structured field'ları doğru ayrıştırın
Signature-Input ve Signature, HTTP Structured Fields'tir (RFC 9651, RFC 8941'in yerini alır). Bunları string bölme ile ayrıştırmayın. Tırnaklı dizeler, parametreler ve iç listelerin hepsinin kesin bir grameri vardır ve özensiz bir ayrıştırıcı hem yanlış reddetmelere hem de gerçek güvenlik boşluklarına yol açar.
Bakımı yapılan bir structured-field ayrıştırıcı kullanın ya da daha iyisi, ayrıştırma ve doğrulamayı birlikte yapan bakımı yapılan bir RFC 9421 kütüphanesi kullanın. Belirtimi sıfırdan uygulamak iyi bir öğrenme alıştırmasıdır ama üretim için kötü bir tercihtir. Aşağıdaki adımlar, böyle bir kütüphanenin ne yaptığını anlatır; böylece onu doğru yapılandırabilir ve çıktısını inceleyebilirsiniz.
2. Adım: Hangi imzayı değerlendireceğinizi seçin
Bir istek birden fazla imza etiketi taşıyabilir. Politikanıza uyan etiketi seçin, örneğin tag değeri web-bot-auth olan etiket. Aşağıdakilerden biri varsa isteği doğrulama amaçlı reddedin (sunum amaçlı değil):
- hiçbir imzada sizin istediğiniz parametreler yoksa,
- algorithm izin listenizde değilse, örneğin
ed25519, veya - kapsanan bileşenler sizin istediğiniz asgari kümeyi içermiyorsa.
Otomatik istemciler için makul bir asgari küme @method, @authority ve @path'tir; o başlık mevcutsa signature-agent de eklenir. @authority olmadan bir site için yakalanmış bir imza başka bir siteye karşı yeniden oynatılabilir. @path olmadan uç noktalar arasında yeniden kullanılabilir. Web Bot Auth protokol taslağı agent'ların @authority veya @target-uri'u kapsamasını ister ve yalnızca authority'yi kapsayan bir imzanın, süresi dolana kadar bu host üzerindeki herhangi bir method veya path'e karşı doğrulandığını belirtir.
3. Adım: Zaman parametrelerini kontrol edin
RFC 9421, Bölüm 2.3'te tanımlanan zaman parametreleri created ve expires'yi okuyun. Ardından:
createdzamanı küçük bir saat sapması payının ötesinde gelecekte olan imzaları reddedin.expiressüresini geçmiş imzaları reddedin.expiresyoksa,created'a dayanarak kendi azami yaş sınırınızı uygulayın.
Kısa geçerlilik pencereleri, yakalanan bir isteğin ne kadar süreyle yeniden oynatılabileceğini sınırlar.
4. Adım: Anahtarı bulun
Signature-Agent başlığı operatörün anahtar dizinine işaret eder. Bunu HTTPS üzerinden alın ve yalnızca HTTPS üzerinden. Web Bot Auth protokol taslağı dizini, o origin üzerindeki http-message-signatures-directory well-known URI'den sunulan bir JSON Web Key Set olarak açıklar (JWK formatında anahtarlar). Ardından tanımlayıcısı keyid parametresiyle eşleşen anahtarı bulun.
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;
}Anahtar bulma için pratik kurallar:
- Doğrulamanın her isteğe bir ağ çağrısı eklememesi için anahtarları sınırlı bir süreyle önbelleğe alın.
- Kısa bir zaman aşımı ayarlayın ve başarısız bir alma işlemini hiçbir zaman "doğrulandı" olarak değil, "doğrulanamadı" olarak değerlendirin.
- Mümkünse yalnızca hangi origin'lerden alınacağını sınırlandırın ya da en azından sunucu tarafı istek sahteciliğini önlemek için özel adres aralıklarını engelleyin. Protokol taslağı, güvenlik değerlendirmelerinde bu nedenle server-side request forgery'yi özellikle listeler.
- Kimliği free-text user agent adına değil, origin'e bağlayın. Kaydettiğiniz tanımlayıcı dizin origin'idir.
5. Adım: Signature base'i yeniden oluşturun
İmzalayan ham isteği imzalamadı. Kapsanan bileşenlerden sırayla oluşturulan ve ardından @signature-params satırı eklenen signature base adlı kanonik bir dizeyi (RFC 9421, Bölüm 2.5) imzaladı. Doğrulayıcınız, aldığı istektan aynı dizeyi yeniden oluşturur.
Yukarıdaki örnekte base şöyle görünür:
"@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"Proxy'lerin arkasında doğrulamayı bozan ayrıntılara dikkat edin:
@authority, istemcinin hedeflediği host olmalıdır. Bir load balancerHost'yi yeniden yazıyorsa, ilettiği orijinal değeri kullanın.@path, query string'i dışarıda bırakır. İstemci@query'ü kapsadıysa, onu tam olarak alındığı haliyle yeniden oluşturun.- Header değerleri belirtildiği gibi kanonikleştirilir: kırpılır, birden fazla değer birleştirilir. İyi bir kütüphane bunu sizin için yapar.
6. Adım: İmzayı doğrulayın
Base ve açık anahtar ile doğrulama, RFC 9421, Bölüm 3.2'deki adımları izleyen tek bir çağrıdır. Node.js'te Ed25519 için, yerleşik crypto module kullanarak:
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"));
}Kontrol başarısız olursa, istek doğrulanmamıştır. Yine de sunulabilir. Sadece "verified" basis'i almaz.
7. Adım: Yeniden oynatmayı önleyin
Geçerli bir imza, süresi dolana kadar yakalanıp yeniden gönderilebilir. RFC 9421, Bölüm 7.2.2 signature replay'i kapsar ve Web Bot Auth protokol taslağı kendi nonce kurallarını eklemek yerine buna dayanır. Bu pencerenin çoğunu kapatan iki kontrol vardır:
-
- Adımda uygulanan kısa expiry.
- Nonce takibi. Bir
noncemevcut olduğunda, süresi dolana kadar onu anahtar tanımlayıcısıyla birlikte paylaşılan bir depoda saklayın ve ikinci kullanımı reddedin.
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;
}Birden çok örnekli dağıtımda nonce'ları, kalan geçerliliğe eşit bir time to live ile Redis gibi paylaşılan bir depoda tutun.
8. Adım: Sonucu basis'iyle kaydedin
Doğrulama bir karar değil, evidence üretir. Bunu analiz ve politikalarınızın kullanabileceği bir biçimde kaydedin:
const result = {
actor: "agent",
basis: "verified",
operator: "https://agent.example",
keyId: "kq1",
coveredComponents: ["@method", "@authority", "@path", "signature-agent"],
verifiedAt: new Date().toISOString(),
};Doğrulama başarısız olursa veya çalışamazsa bunu da nedeni ile kaydedin: eksik başlıklar, desteklenmeyen algorithm, anahtar bulunamadı, süresi doldu, yeniden oynatıldı veya imza eşleşmedi. Bu nedenler değerlidir. Tek bir operatörden gelen "key not found" artışı çoğu zaman saldırı yaptıklarını değil, anahtarlarını döndürdüklerini gösterir.
İmza doğrulamasından neleri kaydetmelisiniz?
Operatör origin'ini, key identifier'ı, kapsanan bileşenleri, zaman parametrelerini, sonucu ve hata nedenini kaydedin. Tam imza baytlarını veya tüm istek gövdelerini kaydetmeyin. Günlükleri, kalıpları inceleyecek kadar uzun ama gizlilik taahhütlerinize uyacak kadar kısa tutun.
Doğrulanmış bir imza politikanızı nasıl değiştirmeli?
İstekler doğrulanabildiğinde, onları anlamlı biçimde farklı ele alabilirsiniz. İnsanlar ve AI agent'lar için uygulama politikaları tasarlama konulu yazımız daha geniş politika modelini anlatır:
- Doğrulanmış operatörlere, doğrulanmamış otomasyona göre daha yüksek rate limit ile salt-okunur route'lara izin verin.
- Onlara tam HTML sayfaları yerine JSON veya Markdown gibi yapılandırılmış yanıtlar sunun.
- Yüksek etki yaratan işlemleri normal authorization sürecinizin arkasında tutun. Doğrulanmış bir imza size hangi istemcinin çağrı yaptığını söyler, bir hesabı değiştirebileceğini değil.
Gözlem modunda başlayın. Herhangi bir politika buna bağlı olmadan önce otomatik trafiğinizin ne kadarının imzalı olduğunu, hangi operatörlerin göründüğünü ve doğrulamanın ne sıklıkta başarısız olduğunu ölçün.
Proof of Actor burada nereye oturur?
İmza doğrulama, birkaç kaynaktan biri olan evidence kaynaklarından biridir. Proof of Actor bunu başka sinyallerle birleştirir ve basis'i her sonuçta görünür tutar, böylece doğrulanmış bir agent yalnızca kendini beyan eden bir agent ile asla karıştırılmaz. Bundan sonra ne olacağına uygulamanız karar verir.
Bunu mühendislerimizle birlikte üretim uygulamasına taşımak için erken erişim için başvurun. Evidence'ın neyi gösterip neyi gösteremediğinin tam resmi için Detection & Limitations okuyun.
Kaynaklar
- RFC 9421: HTTP Message Signatures: signature parameters, signature base ve replay değerlendirmelerini içeren imzalama ve doğrulama standardı
- RFC 9651: Structured Field Values for HTTP:
Signature-InputveSignaturetarafından kullanılan gramer - IETF Web Bot Auth çalışma grubu: otomatik istemci authentication çalışmasının charter ve durumu
- draft-ietf-webbotauth-httpsig-protocol:
Signature-Agent, JWKS anahtar dizini ve well-known URI'yi tanımlayan Internet-Draft (Kasım 2026 itibarıyla çalışma halindedir) - RFC 7517: JSON Web Key (JWK): yayımlanmış anahtar dizinlerinde kullanılan anahtar biçimi
- RFC 8615: Well-Known URIs: anahtar dizini gibi well-known path'lerin nasıl kaydedildiği
- RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA): örnekte kullanılan Ed25519 algorithm'i
- Node.js crypto documentation: 6. Adım'da kullanılan
createPublicKeyveverify