Egy cookie-val hitelesített POST /api/profile kérésnél a szerver önmagában nem tudja, hogy azt a saját felületünk vagy egy idegen oldal rejtett űrlapja indította. A böngésző viszont tudja. A Fetch Metadata fejléc-család ezt a környezetet küldi el a kérés mellé, így a szerver még az alkalmazáskód előtt eldobhatja az egyértelműen gyanús forgalmat.

Négy jelzés, nem négy új hitelesítési adat
A Fetch Metadata specifikáció négy kéréstulajdonságot tesz láthatóvá: Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest és Sec-Fetch-User. A legfontosabb az első. Értékei same-origin, same-site, cross-site vagy none; azt mutatja, milyen viszonyban van a kezdeményező oldal és a cél. A none jellemzően közvetlen, felhasználó által indított navigáció, például címsorból vagy könyvjelzőből.
A másik három fejléc finomít. A Sec-Fetch-Mode megkülönbözteti például a navigációt és a cors kérést, a Sec-Fetch-Dest azt jelzi, dokumentumot, képet, scriptet vagy más cél-erőforrást kérnek-e, a Sec-Fetch-User: ?1 pedig felhasználói aktivációhoz kötött navigációnál jelenhet meg. Ezeket érdemes policyhez használni, de a CSRF-szerű kérések szűrésének fő jele a Sec-Fetch-Site.
Ez nem egy frontendes konvenció. A Sec- előtag miatt a weboldal JavaScriptje nem állíthatja át ezeket a fejléceket. Ettől még nem válnak hitelesítéssé: a szervernek továbbra is ellenőriznie kell a sessiont, a jogosultságokat és a bemenetet. Viszont egy külső oldal nem tudja egyszerűen same-origin-nek álcázni a böngészőből indított kérését.
Egy szűk, érthető policy
Cookie-s munkamenetet használó JSON API-nál jó alapelv, hogy az állapotmódosító metódusoknál a cross-site mindig tiltott. A same-origin mehet. A same-site viszont nem ugyanaz: egy másik, azonos regisztrálható domain alatti aldomainről is érkezhet. Ha például egy partner, régi szolgáltatás vagy felhasználói tartalom él valami.example.com alatt, ezt ne tekintsük automatikusan megbízhatónak.
import assert from 'node:assert/strict';
const unsafeMethods = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
function isTrustedOrigin(origin) {
return origin === 'https://app.example.com';
}
function allowRequest({ method, secFetchSite, origin }) {
if (!unsafeMethods.has(method)) return true;
if (secFetchSite === 'cross-site') return false;
if (secFetchSite === 'same-origin') return true;
if (secFetchSite === 'same-site') return false;
// Hiányzó, ismeretlen vagy `none` értéknél fallback következik.
return isTrustedOrigin(origin);
}
assert.equal(allowRequest({ method: 'POST', secFetchSite: 'cross-site' }), false);
assert.equal(allowRequest({ method: 'POST', secFetchSite: 'same-origin' }), true);
assert.equal(allowRequest({ method: 'PATCH', origin: 'https://app.example.com' }), true);
Expressben vagy Fastifyban ezt middleware-ből, az útvonalkezelő előtt lehet meghívni a bejövő sec-fetch-site és origin fejléc értékével. A példa szándékosan zárt: ismeretlen fejlécértéknél a specifikáció szerinti „ignoráld a jelet” viselkedést egy ismert Origin-ellenőrzésre fordítja. Csak azután engedélyezzük a same-site-ot, ha az összes testvér aldomain biztonságosan a mi kontrollunk alatt van.
Fontos határvonal, hogy ez az információ a böngészőtől jön. Egy szerver–szerver webhook, egy mobil kliens vagy a saját curl-tesztünk természetesen nem ugyanilyen fejlécet küld. Ez nem hiba, hanem oka annak, hogy a policyt az interaktív, cookie-val hitelesített webes végpontokra célszerű szűkíteni. A gépi integrációknak külön útvonal, aláírás vagy API-kulcs kell; ne a böngészőre tervezett jel hiánya döntsön róluk.
A hiányzó fejléc is tervezési eset
A Fetch Metadata csak megbízható URL-ekhez kapcsolódó böngészőkérésekben érkezik, és régi vagy beágyazott kliens hiányosan küldheti. Emiatt nem szabad azt mondani, hogy „ha nincs Sec-Fetch-Site, akkor biztos saját kérés”. Az OWASP CSRF útmutatója is kötelező fallbackként említi az Origin/Referer-ellenőrzést vagy tokenes védelmet. Érzékeny végpontnál a hiányzó jel inkább legyen tiltás; kompatibilitásra szoruló rendszernél csak a meglévő, valódi CSRF-védelmi ellenőrzéssel együtt engedjük tovább.
A publikus webhookok, harmadik féltől hívható API-k és szándékosan cross-origin CORS-végpontok külön kivételt kérnek, saját hitelesítéssel és naplózással. Ugyanezért a globális middleware előtt vagy mellett gondosan soroljuk fel őket. Állapotot pedig GET-tel ne módosítsunk: azt a példabeli policy is átengedi, mert a biztonságos HTTP-metódus erre való.
A bevezetés kockázatmentes módja a log-only időszak. Először rögzítsük, mely kéréseket utasítanánk el, nézzük át a legitim integrációkat, majd kapcsoljuk be a tiltást. Ha a válasz tartalma tényleg függ a fejlécértéktől, a cache-rétegnek is jelezni kell ezt, például Vary: Sec-Fetch-Site, Origin fejlécben. Így a böngésző által amúgy is ismert kontextus egy rövid, jól auditálható szerveroldali védelmi réteggé válik.