Connection-Allowlist HTTP রেসপন্স হেডার কোনও ডকুমেন্ট বা ওয়ার্কারকে নেটওয়ার্ক এন্ডপয়েন্টের একটি নির্দিষ্ট তালিকার সাথে যোগাযোগ করার ক্ষেত্রে সীমাবদ্ধ করে। কন্টেন্ট নিরাপত্তা নীতি (CSP)—যার জন্য প্রতিটি রিসোর্স অনুযায়ী আলাদা নির্দেশিকা (connect-src, img-src, script-src, font-src, form-action) বজায় রাখতে হয় এবং যা <link rel="dns-prefetch">, <link rel="preconnect"> বা WebRTC-এর মতো স্পেকুলেটিভ বা নন-ফেচ নেটওয়ার্ক চ্যানেল নিয়ন্ত্রণ করে না—তার থেকে আলাদাভাবে Connection-Allowlist, কনটেক্সট (fetch(), XMLHttpRequest, সাবরিসোর্স, navigator.sendBeacon(), <a ping>, টপ-লেভেল ও ফ্রেম নেভিগেশন, রিসোর্স হিন্ট, স্পেকুলেশন রুল, WebSocket, WebTransport ও WebRTC) দ্বারা শুরু করা সব আউটবাউন্ড কানেকশন জুড়ে একটি একক, নেটওয়ার্ক-লেয়ার সাদাতালিকা প্রয়োগ করে।
কীভাবে প্রয়োগ করতে হয়
- RFC 9651 ইনার লিস্ট হিসেবে অনুমোদিত তালিকা সিরিয়ালাইজ করুন
(...):Connection-Allowlist(বাConnection-Allowlist-Report-Only) স্পেস দিয়ে আলাদা করা আইটেমের বন্ধনীতে থাকা একটি তালিকা হিসেবে ফর্ম্যাট করুন। ডকুমেন্ট বা ওয়ার্কারের নিজস্ব অরিজিনকে অনুমতি দিতে, কোটেশন ছাড়া টোকেনresponse-originযোগ করুন, তারপরে প্রতিটি বৈধ এক্সটার্নাল এন্ডপয়েন্টের জন্য ডবল কোটেশন সহURLPatternস্ট্রিং যোগ করুন, যার সাথে কন্টেক্সট কানেক্ট করে বা নেভিগেট করে (API, ছবি/ফন্ট CDN এবং আউটবাউন্ড<a href>,<form action>, OAuth বা পেমেন্ট রিডাইরেক্ট টার্গেট)। কনফিগারেশন বাURLঅবজেক্ট থেকে ডায়নামিকালি প্যাটার্ন তৈরি করার সময়,ws:/wss:-কেhttp:/https:-এ নরমালাইজ করুন এবং শুধুমাত্র-অরিজিন URL-এ শেষে থাকা স্ল্যাশ বাদ দিন (কারণnew URL('https://api.example.com').href/যোগ করে, যাURLPattern-কে শুধুমাত্র রুট পাথ/-এর সাথে ম্যাচ করার জন্য সীমাবদ্ধ করে)। Sec-Fetch-Dest-এর মাধ্যমে মিডলওয়্যার স্কোপ করুন এবং ওয়ার্কার কভার করুন: ব্রাউজার শুধুমাত্র ডকুমেন্ট/নেভিগেশন রেসপন্স এবং ওয়ার্কার স্ক্রিপ্ট রেসপন্সে (Sec-Fetch-Destভ্যালুdocument,iframe,worker,sharedworkerএবংserviceworker)Connection-Allowlist-কে সম্মান করে।Sec-Fetch-Dest-এর মাধ্যমে হেডার পরিবর্তন করার সময়,Vary: Sec-Fetch-Destঅন্তর্ভুক্ত করুন যাতে শেয়ার করা ক্যাশে হেডারলেস রেসপন্স পরিবেশন না করে। ডেডিকেটেড ও শেয়ার করা ওয়ার্কার স্ক্রিপ্টে একটি ম্যাচিং সাদাতালিকা পরিবেশন করুন যাতে আপোস করা পৃষ্ঠা স্ক্রিপ্টworker.postMessage()-এর মাধ্যমে ডেটা এক্সফিল্ট্রেট করতে না পারে। যেহেতু কোনও সার্ভিস ওয়ার্কার ক্যাশে মিস ও নেভিগেশন প্রিলোডের ক্ষেত্রে নিজস্ব নেটওয়ার্ক ফেচ পারফর্ম করে, তাই এটি নিয়ন্ত্রণ করে এমন সব ডকুমেন্টের অনুমোদিত তালিকার সুপারসেট হিসেবে এরConnection-Allowlistকনফিগার করুন।- লঙ্ঘন সংক্রান্ত রিপোর্টিং এবং স্টেজড বা ডুয়াল রোলআউট কনফিগার করা:
Reporting-Endpointsহেডার নির্দিষ্ট করুন এবং বন্ধ করার)-এর পরে উদ্ধৃতিচিহ্ন ছাড়া; report-to=<endpoint-name>প্যারামিটার যোগ করুন। প্রাথমিক রোলআউটের সময় আপনি শুধুConnection-Allowlist-Report-Onlyপাঠাতে পারেন অথবা একই উত্তরে উভয়Connection-Allowlist(বেসলাইন অনুমোদিত তালিকা এনফোর্স করা) এবংConnection-Allowlist-Report-Only(আরও কঠোর ক্যান্ডিডেট অনুমোদিত তালিকা অডিট করা) পাঠাতে পারেন। লঙ্ঘনের রিপোর্ট"type": "connection-allowlist"এবং বডি{ url, connection, allowlist, disposition }সহ ডেলিভার করা হয় (যেখানেconnectionহল ব্লক করা গন্তব্য URL বা"webrtc"এবংdispositionহল"enforce"বা"report")। - ডিফল্ট রিডাইরেক্ট ও WebRTC ব্লক করার জন্য অ্যাকাউন্ট এবং ক্লায়েন্ট সংক্রান্ত সমস্যার সমাধান করা: ডিফল্ট হিসেবে,
Connection-Allowlistসব3xxHTTP রিডাইরেক্ট (redirects=block, এমনকি সাদা তালিকায় থাকা বা একই-উৎসের URL-এর মধ্যে রিডাইরেক্ট করার সময়ও) এবং সবRTCPeerConnectionট্রাফিক (webrtc=block) ব্লক করে। শুধুমাত্র বিশ্বস্ত এন্ডপয়েন্টের জন্য সার্ভার-সাইড রিডাইরেক্টের প্রয়োজন হলে (প্রাথমিক অনুরোধটি এখনও সাদা তালিকার সাথে মিলতে হবে); redirects=allowযোগ করুন অথবা WebRTC-এর প্রয়োজন হলে; webrtc=allowযোগ করুন। ক্লায়েন্টে, আউটবাউন্ডfetch()কলtry...catch-এ র্যাপ করুন এবংWebSocketerrorইভেন্ট ম্যানেজ করুন যাতেTypeError(net::ERR_NETWORK_ACCESS_REVOKED) সহ বাতিল করা অনুরোধ ম্যানেজ করা হয়েছে এমন সমস্যা সংক্রান্ত স্ট্যাটাস ফিরিয়ে দেয় এবং ম্যানেজ করা হয়নি এমন বাতিলকরণের পরিবর্তে UI স্ট্যাটাস আপডেট করে।
কোডের উদাহরণ
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 };
}
}
পেশাদার পদ্ধতি
- DO format
Connection-Allowlistas a single RFC 9651 Inner List(...)of space-separated items. খালি নয় এমনConnection-Allowlistহেডার টপ-লেভেল স্ট্রাকচার্ড ফিল্ড পার্সিং (যেমন,(...)বাদ দেওয়া বা সিঙ্গল কোট'...'ব্যবহার করা) করতে না পারলে, ব্রাউজার খালি অনুমোদিত তালিকা সহ বন্ধ হয়ে যায় এবং সব আউটবাউন্ড নেটওয়ার্ক কানেকশন ব্লক করে দেয়। লোড করার পরে আপনি ইচ্ছাকৃতভাবে সব নেটওয়ার্ক অ্যাক্সেস তুলে নিতে চাইলেConnection-Allowlist: ()ব্যবহার করুন (লোকাল স্কিমdata:,blob:,about:এবংfilesystem:অনুমোদিত থাকবে)। - অরিজিন-ওয়াইড URL প্যাটার্নে (
"https://api.example.com") ট্রেলিং স্ল্যাশ বাদ দেবেন অথবা একটি এক্সপ্লিসিট ওয়াইল্ডকার্ড ("https://api.example.com/*") ব্যবহার করবেন যাতে/v1/users-এর মতো সাবপাথ অনুমোদিত হয়। প্যাটার্ন সিরিয়ালাইজ করার আগেnew URL(origin).href-এর যোগ করা ট্রেলিং স্ল্যাশ স্ট্রিপ করুন। Connection-Allowlist-এ"http://..."এবং"https://..."প্যাটার্ন ব্যবহার করেWebSocket(ws://এবংwss://) এন্ডপয়েন্টকে অনুমতি তালিকায় রাখুন, কারণ ব্রাউজার মেলানোর আগে WebSocket স্কিমকে HTTP/HTTPS-এ নরমালাইজ করে।- অবশ্যই প্রত্যাশিত এক্সটার্নাল নেভিগেশন টার্গেট (
<a href>,<form action>, OAuth/SSO প্রোভাইডার, পেমেন্ট চেক-আউট) কোনও সীমাবদ্ধ ডকুমেন্টের সাদাতালিকায় অন্তর্ভুক্ত করুন এবং মনে রাখবেন যে ডিফল্টredirects=blockএমনকি একই-উৎসের3xxরিডাইরেক্টও ব্লক করে, যদি না; redirects=allowনির্দিষ্ট করা থাকে। response-originবা ইনার-লিস্ট প্যারামিটারের মান (; report-to=conn-reports,; redirects=allow,; webrtc=allow) কোটেশনের মধ্যে র্যাপ করবেন না অথবা(...)-এর মধ্যে থাকা আইটেম কমা দিয়ে আলাদা করবেন না।- URL প্যাটার্নের মধ্যে
(\d+)-এর মতো কাস্টম রেগুলার এক্সপ্রেশন গ্রুপ অথবা"/api/*"-এর মতো রিলেটিভ পাথ ব্যবহার করবেন না; ব্রাউজারের নেটওয়ার্ক-পরিষেবা পার্সার, স্কিম ও হোস্টনেম ছাড়া regex গ্রুপ ও প্যাটার্ন বাতিল করে দেয়। - প্রোডাকশনে এখনও পরীক্ষামূলক
<iframe connectionAllowlist="...">অ্যাট্রিবিউট বাAllow-Connection-Allowlist-Fromএম্বেড করা এনফোর্সমেন্ট হেডারের উপর নির্ভর করবেন না, কারণ শিপিং ব্রাউজারে ডিফল্ট হিসেবে এম্বেড করা এনফোর্সমেন্ট চালু করা থাকে না।
ফলব্যাক স্ট্র্যাটেজি
যেহেতু HTTP রেসপন্স হেডারের মাধ্যমে ব্রাউজার নেটওয়ার্ক লেয়ারে Connection-Allowlist এনফোর্স করা হয়, তাই ক্লায়েন্ট-সাইড জাভাস্ক্রিপ্টে এটি পলিফিল করা যায় না। আপনার বেসলাইন টার্গেটে যদি এমন ব্রাউজার অন্তর্ভুক্ত থাকে যা এখনও Connection-Allowlist, পেয়ার Connection-Allowlist-কে Content-Security-Policy (CSP) হেডারের সাথে (এবং HTTP রেসপন্স হেডার কনফিগার করা না গেলে ডকুমেন্ট-লেভেল ফেচ এবং সাবরিসোর্স সংক্রান্ত বিধিনিষেধের জন্য একটি <meta http-equiv="Content-Security-Policy"> এলিমেন্ট) সাপোর্ট করে না:
- অ্যাডিটিভ বিবিধ প্রতিরোধ ব্যবস্থা: যেসব ব্রাউজার এই সুবিধা প্রদান করে সেগুলি দুটি নীতিই একসাথে প্রয়োগ করে—
Connection-Allowlistনন-CSP এক্সফিলট্রেশন চ্যানেল (dns-prefetch,preconnect, WebRTC ও রিডাইরেক্ট) ব্লক করে, যেখানে CSPConnection-Allowlistছাড়া ব্রাউজারেfetch(), সাবরিসোর্স ও<form action>নেভিগেশন সীমাবদ্ধ করে। form-actionএবংworker-srcস্পষ্টভাবে কভার করুন: CSP-তে,<form action>জমা দেওয়ার জন্যdefault-srcফলব্যাক করে না; সবসময় স্পষ্টভাবেform-actionঅন্তর্ভুক্ত করুন।worker-src 'self'(blob:বাদ দিয়ে) অন্তর্ভুক্ত করুন যাতে বিধিনিষেধযুক্ত পৃষ্ঠা ডকুমেন্ট-লেভেল বিধিনিষেধ বাইপাস করার জন্যblob:SharedWorkers স্পন করতে না পারে।- প্রতি-রিসোর্স CSP ডিরেক্টিভে অনুমোদিত অরিজিন ম্যাপ করুন:
Connection-Allowlist-এর (যা একটি সিঙ্গেল এন্ডপয়েন্ট তালিকা ব্যবহার করে এবং ইনলাইন মার্কআপ পরিচালনা করে না) মতো নয়, CSP-তেdefault-src 'self'প্রতিটি রিসোর্সের ধরন (connect-src,img-src,style-src,font-src,script-src) সীমাবদ্ধ করে এবং হ্যাশ বা ননসের মাধ্যমে অনুমোদিত না হলে ইনলাইন<style>এবং<script>ব্লক করে। - CSP
connect-src-এwss://অন্তর্ভুক্ত করুন:Connection-Allowlist,"https://..."প্যাটার্নের সাথেwss://কানেকশন ম্যাচ করলেও, ক্রস-ব্রাউজার এনভায়রনমেন্টে CSPconnect-src-এর ক্ষেত্রে WebSocket ব্যবহার করা হলে,wss://-এর সোর্স স্পষ্টভাবে তালিকাভুক্ত করতে হবে।
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'"
/>