From bdde4534f6234e1a124bb488c0bacd605ffa319d Mon Sep 17 00:00:00 2001 From: ht Date: Sun, 6 Sep 2026 18:18:19 +0300 Subject: [PATCH] vary CORS responses by origin --- docs/quality/uygulama-durumu.md | 6 ++++++ server/index.js | 3 +++ tests/http-state.test.mjs | 1 + 3 files changed, 10 insertions(+) diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md index 397834f..d12e9a4 100644 --- a/docs/quality/uygulama-durumu.md +++ b/docs/quality/uygulama-durumu.md @@ -2030,3 +2030,9 @@ Doğrulama: 288 test geçti, üretim derlemesi başarılı. HTTP test sunucusu artık yapılandırılmış iki izinli origin ile başlatılıyor; izinli origin preflight yanıtında geri dönerken tanımsız origin CORS başlığı alamıyor. Böylece allowlist davranışı gerçek süreç üzerinden doğrulanıyor. Doğrulama: HTTP testleri 19/19, toplam 288 test geçti; üretim derlemesi başarılı. + +### 2026-09-06 · CORS yanıtlarında önbellek ayrımı + +Origin allowlistesi etkin olduğunda API ve preflight yanıtlarına `Vary: Origin` eklendi; farklı origin’lere ait CORS yanıtlarının ara önbellekte birbirine karışması engellendi. + +Doğrulama: 288 test geçti, üretim derlemesi başarılı. diff --git a/server/index.js b/server/index.js index 3ff4b80..7daaf36 100644 --- a/server/index.js +++ b/server/index.js @@ -629,6 +629,7 @@ function json(res, code, body) { 'Referrer-Policy': 'no-referrer', }; const origin = res.__ihaleistCorsOrigin; + if (CORS_ORIGINS.length) headers.Vary = 'Origin'; if (origin) headers['Access-Control-Allow-Origin'] = origin; else if (!CORS_ORIGINS.length) headers['Access-Control-Allow-Origin'] = '*'; res.writeHead(code, headers); @@ -740,10 +741,12 @@ const server = http.createServer(async (req, res) => { res.__ihaleistCorsOrigin = CORS_ORIGINS.length && CORS_ORIGINS.includes(requestOrigin) ? requestOrigin : null; if (req.method === 'OPTIONS') { const headers = { + 'Vary': CORS_ORIGINS.length ? 'Origin' : undefined, 'Access-Control-Allow-Methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS', 'Access-Control-Allow-Headers': 'Authorization,Content-Type', 'Access-Control-Max-Age': '600', }; + if (!headers.Vary) delete headers.Vary; if (res.__ihaleistCorsOrigin) headers['Access-Control-Allow-Origin'] = res.__ihaleistCorsOrigin; else if (!CORS_ORIGINS.length) headers['Access-Control-Allow-Origin'] = '*'; res.writeHead(204, headers); diff --git a/tests/http-state.test.mjs b/tests/http-state.test.mjs index 40aa58c..b5fc61e 100644 --- a/tests/http-state.test.mjs +++ b/tests/http-state.test.mjs @@ -29,6 +29,7 @@ test('HTTP preparation requires auth, persists draft and rejects stale revisions const preflight=await fetch(base+'/api/me/plan',{method:'OPTIONS',headers:{Origin:'https://client.example', 'Access-Control-Request-Method':'GET', 'Access-Control-Request-Headers':'authorization,content-type'}}); assert.equal(preflight.status,204); assert.equal(preflight.headers.get('access-control-allow-origin'),'https://client.example'); + assert.equal(preflight.headers.get('vary'),'Origin'); assert.equal(preflight.headers.get('access-control-allow-headers'),'Authorization,Content-Type'); const denied=await fetch(base+'/api/me/plan',{method:'OPTIONS',headers:{Origin:'https://untrusted.example','Access-Control-Request-Method':'GET'}}); assert.equal(denied.status,204);assert.equal(denied.headers.get('access-control-allow-origin'),null);