Connection-Allowlist HTTP yanıt başlığı, bir dokümanın veya çalışanın yalnızca açık bir ağ uç noktası listesiyle iletişim kurmasını kısıtlar. Ayrı kaynak başına yönergelerin (connect-src, img-src, script-src, font-src, form-action) sürdürülmesini gerektiren ve <link rel="dns-prefetch">, <link rel="preconnect"> veya WebRTC gibi spekülatif ya da Fetch olmayan ağ kanallarını yönetmeyen İçerik Güvenliği Politikası'nın (CSP) aksine Connection-Allowlist, bağlam tarafından başlatılan tüm giden bağlantılarda (fetch(), XMLHttpRequest, alt kaynaklar, navigator.sendBeacon(), <a ping>, üst düzey ve çerçeve gezinmeleri, kaynak ipuçları, spekülasyon kuralları, WebSocket, WebTransport ve WebRTC) tek bir ağ katmanı izin verilenler listesi uygular.
Nasıl uygulanır?
- İzin verilenler listesini RFC 9651 İç Listesi olarak serileştirin
(...):Connection-Allowlist(veyaConnection-Allowlist-Report-Only) öğesini, boşlukla ayrılmış öğelerden oluşan tek bir parantez içine alınmış liste olarak biçimlendirin. Dokümanın veya çalışanın kendi kaynağına izin vermek için tırnak içine alınmamışresponse-originjetonunu ekleyin. Ardından, bağlamın bağlandığı veya gittiği her meşru harici uç nokta (API'ler, resim/yazı tipi CDN'leri ve giden<a href>,<form action>, OAuth veya ödeme yönlendirme hedefleri) için çift tırnak içine alınmışURLPatterndizelerini ekleyin. Yapılandırma veyaURLnesnelerinden dinamik olarak kalıp oluştururkenws:/wss:değerinihttp:/https:olarak normalleştirin ve yalnızca kaynak URL'lerdeki sondaki eğik çizgileri kaldırın (çünkünew URL('https://api.example.com').href,/ekler ve bu daURLPatterneşleşmesini yalnızca kök yol/ile kısıtlar). - Ara katman yazılımlarını
Sec-Fetch-Destile kapsamlandırın ve çalışanları kapsayın: Tarayıcılar, yalnızca belge/gezinme yanıtlarında ve çalışan komut dosyası yanıtlarında (Sec-Fetch-Destdeğerleridocument,iframe,worker,sharedworkerveserviceworker)Connection-Allowlistdeğerini dikkate alır. ÜstbilgileriSec-Fetch-Destile değiştirirkenVary: Sec-Fetch-Destdeğerini ekleyin. Böylece paylaşılan önbellekler üstbilgisiz yanıtlar sunmaz. Özel ve paylaşılan çalışan komut dosyalarında eşleşen bir izin verilenler listesi sunun. Böylece güvenliği ihlal edilmiş sayfa komut dosyalarıworker.postMessage()üzerinden veri sızdıramaz. Hizmet Çalışanı, önbellekte yok ve gezinme önceden yüklemelerinde kendi ağ getirme işlemlerini gerçekleştirdiğindenConnection-Allowlistdeğerini, kontrol ettiği tüm dokümanların izin verilenler listelerinin süper seti olarak yapılandırın. - İhlal raporlamasını ve aşamalı veya ikili sunumu yapılandırın: Bir
Reporting-Endpointsüstbilgisi tanımlayın ve kapanış)işaretinden sonra tırnak içine alınmamış bir; report-to=<endpoint-name>parametresi ekleyin. İlk kullanıma sunma sırasında yalnızcaConnection-Allowlist-Report-Onlygönderebilir veya aynı yanıtta hemConnection-Allowlist(temel izin verilenler listesini zorunlu kılar) hem deConnection-Allowlist-Report-Only(daha katı bir aday izin verilenler listesini denetler) gönderebilirsiniz. İhlal raporları"type": "connection-allowlist"ve{ url, connection, allowlist, disposition }gövdesiyle gönderilir (buradaconnection, engellenen hedef URL veya"webrtc",dispositionise"enforce"ya da"report"şeklindedir). - Varsayılan yönlendirme ve WebRTC engellemesini hesaba katın ve istemci hatalarını işleyin: Varsayılan olarak
Connection-Allowlist, tüm3xxHTTP yönlendirmelerini (redirects=block, izin verilenler listesindeki veya aynı kaynak URL'ler arasında yönlendirme yaparken bile) ve tümRTCPeerConnectiontrafiğini (webrtc=block) engeller.; redirects=allowparametresini yalnızca güvenilir uç noktalar sunucu tarafı yönlendirmeleri gerektirdiğinde (ilk istek yine de izin verilenler listesiyle eşleşmelidir) veya WebRTC gerektiğinde; webrtc=allowparametresini ekleyin. İstemcide, gidenfetch()çağrılarınıtry...catchile sarmalayın veWebSocketerroretkinliklerini işleyin. BöyleceTypeError(net::ERR_NETWORK_ACCESS_REVOKED) ile reddedilen istekler, işlenmeyen retlere neden olmak yerine işlenen bir hata durumu döndürür ve kullanıcı arayüzü durumunu günceller.
Örnek kod
Vary: Sec-Fetch-Dest
Reporting-Endpoints: conn-reports="https://app.example.com/api/security-reports"
Connection-Allowlist: (response-origin "https://api.example.com" "https://realtime.example.com" "https://*.cdn.example.com/*"); report-to=conn-reports
Connection-Allowlist-Report-Only: (response-origin "https://api.example.com/v2/*"); report-to=conn-reports
const ALLOWLIST_DESTS = new Set(['document', 'iframe', 'worker', 'sharedworker', 'serviceworker']);
// Normalize a config URL or URLPattern string for Connection-Allowlist:
// - Rewrites ws:// and wss:// to http:// and https:// (WebSocket matching rule).
// - Strips a bare trailing slash on origin-only URLs (e.g. from new URL(...).href)
// so all subpaths on the origin are permitted instead of only "/".
export function normalizeAllowlistPattern(rawPattern) {
const trimmed = String(rawPattern).trim().replace(/^ws(s?):\/\//i, 'http$1://');
if (!/^https?:\/\//i.test(trimmed)) {
throw new Error(`Pattern must include an http:// or https:// scheme: ${rawPattern}`);
}
if (/[\s,]/.test(trimmed)) {
throw new Error(`Pattern must be a single URLPattern without spaces or commas: ${rawPattern}`);
}
if (/[()]/.test(trimmed)) {
throw new Error(`Custom regex groups are rejected by Connection-Allowlist: ${rawPattern}`);
}
return trimmed.replace(/^(https?:\/\/[^/?#]+)\/$/i, '$1');
}
// Build an RFC 9651 Inner List value for Connection-Allowlist or Connection-Allowlist-Report-Only.
export function buildConnectionAllowlistHeader({
allowSelf = true,
patterns = [],
reportTo,
redirects = 'block',
webrtc = 'block',
} = {}) {
const items = allowSelf ? ['response-origin'] : [];
for (const pattern of patterns) {
const raw = String(pattern).trim();
if (raw === 'response-origin') {
if (!items.includes('response-origin')) items.push('response-origin');
continue;
}
const normalized = normalizeAllowlistPattern(raw);
items.push(`"${normalized.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`);
}
let header = `(${items.join(' ')})`;
if (redirects === 'allow') header += '; redirects=allow';
if (webrtc === 'allow') header += '; webrtc=allow';
if (reportTo) {
const endpointToken = String(reportTo).trim().replace(/^"+|"+$/g, '');
header += `; report-to=${endpointToken}`;
}
return header;
}
// Server or middleware helper applying Connection-Allowlist and Reporting-Endpoints
// on document and worker responses.
export function setConnectionAllowlistHeaders(res, options = {}) {
const {
secFetchDest = 'document',
patterns = ['https://api.example.com', 'https://realtime.example.com', 'https://*.cdn.example.com/*'],
reportOnlyPatterns,
reportEndpointName = 'conn-reports',
reportEndpointUrl = 'https://app.example.com/api/security-reports',
redirects = 'block',
webrtc = 'block',
reportOnly = false,
} = options;
const setHeader = (name, value) =>
typeof res.setHeader === 'function' ? res.setHeader(name, value) : res.headers.set(name, value);
if (typeof res.appendHeader === 'function') {
res.appendHeader('Vary', 'Sec-Fetch-Dest');
} else if (typeof res.headers?.append === 'function') {
res.headers.append('Vary', 'Sec-Fetch-Dest');
} else {
setHeader('Vary', 'Sec-Fetch-Dest');
}
if (secFetchDest && !ALLOWLIST_DESTS.has(String(secFetchDest).toLowerCase())) return;
setHeader('Reporting-Endpoints', `${reportEndpointName}="${reportEndpointUrl}"`);
setHeader(
reportOnly ? 'Connection-Allowlist-Report-Only' : 'Connection-Allowlist',
buildConnectionAllowlistHeader({ allowSelf: true, patterns, reportTo: reportEndpointName, redirects, webrtc }),
);
if (!reportOnly && Array.isArray(reportOnlyPatterns)) {
setHeader(
'Connection-Allowlist-Report-Only',
buildConnectionAllowlistHeader({
allowSelf: true,
patterns: reportOnlyPatterns,
reportTo: reportEndpointName,
redirects,
webrtc,
}),
);
}
}
// Client-side helper that catches blocked outbound requests gracefully without unhandled rejections.
export async function fetchWithPolicyHandling(url, { statusElement, ...fetchOptions } = {}) {
try {
const response = await fetch(url, fetchOptions);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const body = await response.text();
if (statusElement) {
statusElement.textContent = `Allowed: Loaded ${url} (${body.length} bytes).`;
}
return { ok: true, body, error: null };
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
if (statusElement) {
statusElement.textContent = `Blocked: Request to ${url} was rejected by the outbound connection policy (${message}).`;
}
return { ok: false, body: null, error };
}
}
En iyi uygulamalar
Connection-Allowlistdeğerini, boşlukla ayrılmış öğelerden oluşan tek bir RFC 9651 iç listesi(...)olarak biçimlendirin (DO). Boş olmayan birConnection-Allowlistüstbilgisi, üst düzey Yapılandırılmış Alan ayrıştırmasında başarısız olursa (örneğin,(...)atlanırsa veya tek tırnak'...'kullanılırsa) tarayıcı, boş bir izin verilenler listesiyle başarısız olur ve tüm giden ağ bağlantılarını engeller. Yüklemeden sonra tüm ağ erişimini kasıtlı olarak iptal etmek istediğinizdeConnection-Allowlist: ()kullanın (yerel şemalardata:,blob:,about:vefilesystem:izinli kalır).- Kaynak genelindeki URL kalıplarında (
"https://api.example.com") sondaki eğik çizgiyi ATLAYIN veya açık bir joker karakter ("https://api.example.com/*") kullanın. Böylece/v1/usersgibi alt yollara izin verilir. Kalıpları serileştirmeden öncenew URL(origin).hreftarafından eklenen sondaki eğik çizgileri kaldırın. - Tarayıcı, eşleştirmeden önce WebSocket şemalarını HTTP/HTTPS olarak normalleştirdiğinden
Connection-Allowlistiçinde"http://..."ve"https://..."kalıplarını kullanarakWebSocket(ws://vewss://) uç noktalarına izin verilenler listesinde YER VERİN. - Kısıtlanmış bir dokümanın izin verilenler listesine beklenen harici gezinme hedeflerini (
<a href>,<form action>, OAuth/SSO sağlayıcıları, ödeme kasaları) EKLEYİN ve varsayılanredirects=blockdeğerinin,; redirects=allowbelirtilmediği sürece aynı kaynaklı3xxyönlendirmelerini bile engellediğini unutmayın. response-originveya iç liste parametre değerlerini (; report-to=conn-reports,; redirects=allow,; webrtc=allow) tırnak içine ALMAYIN ya da(...)içindeki öğeleri virgülle ayırmayın.- URL kalıplarında
(\d+)gibi özel normal ifade grupları veya"/api/*"gibi göreli yollar KULLANMAYIN. Tarayıcının ağ hizmeti ayrıştırıcısı, şema ve ana makine adı içermeyen normal ifade gruplarını ve kalıplarını reddeder. - Yerleşik yaptırım, tarayıcılarda varsayılan olarak etkinleştirilmediğinden henüz üretimde deneysel
<iframe connectionAllowlist="...">özelliğine veyaAllow-Connection-Allowlist-Fromyerleşik yaptırım başlığına GÜVENMEYİN.
Yedek strateji
Connection-Allowlist, bir HTTP yanıt başlığı aracılığıyla tarayıcı ağ katmanında uygulandığından istemci tarafı JavaScript'te polyfill uygulanamaz. Temel hedefiniz henüz Connection-Allowlist özelliğini desteklemeyen tarayıcılar içeriyorsa Connection-Allowlist özelliğini Content-Security-Policy (CSP) başlığıyla eşleyin (ve HTTP yanıt başlıkları yapılandırılamadığında belge düzeyinde getirme ve alt kaynak kısıtlamaları için <meta http-equiv="Content-Security-Policy"> öğesi kullanın):
- Eklemeli derinlemesine savunma: Destekleyen tarayıcılar her iki politikayı da aynı anda uygular.
Connection-Allowlist, İGP dışı veri sızdırma kanallarını (dns-prefetch,preconnect, WebRTC ve yönlendirmeler) engellerken İGP,Connection-Allowlistolmayan tarayıcılardafetch(), alt kaynaklar ve<form action>gezinmelerini kısıtlar. form-actionveworker-srcöğelerini açıkça kapsayın: CSP'dedefault-src,<form action>gönderimleri için yedek olarak kullanılmaz;form-actionöğesini her zaman açıkça ekleyin. Kısıtlanmış sayfaların, belge düzeyindeki kısıtlamaları atlamak içinblob:SharedWorker'lar oluşturamaması amacıylaworker-src 'self'(blob:hariç) ekleyin.- İzin verilen kaynakları kaynak başına İGP yönergeleriyle eşleyin: Tek bir uç nokta listesi kullanan ve satır içi işaretlemeyi yönetmeyen
Connection-Allowlist'nin aksine, İGP'dekidefault-src 'self'her kaynak türünü (connect-src,img-src,style-src,font-src,script-src) kısıtlar ve karma veya tek seferlik rastgele sayılar aracılığıyla yetkilendirilmediği sürece satır içi<style>ve<script>bloklarını engeller. - İGP
connect-src'yewss://ekleyin:Connection-Allowlist,wss://bağlantılarını"https://..."kalıplarıyla eşleştirirken tarayıcılar arası ortamlardaki İGPconnect-src, WebSockets kullanıldığındawss://kaynaklarını açıkça listelemelidir.
Content-Security-Policy: default-src 'self'; connect-src 'self' https://api.example.com https://realtime.example.com wss://realtime.example.com; img-src 'self' https://*.cdn.example.com data: blob:; form-action 'self'; worker-src 'self'; object-src 'none'; base-uri 'self'; report-to conn-reports
<!-- Document-level fallback when HTTP response headers cannot be set on static hosting -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; connect-src 'self' https://api.example.com https://realtime.example.com wss://realtime.example.com; img-src 'self' https://*.cdn.example.com data: blob:; form-action 'self'; worker-src 'self'; object-src 'none'; base-uri 'self'"
/>