Skip to content

এজে সিকিউরিটি

DDoS শোষণ, WAF, রেট লিমিট, বট, origin লুকানো, signed URL, আর দুইটা আক্রমণ যেগুলো CDN-এর নিজের ক্যাশকে অস্ত্র বানায়: cache poisoning ও cache deception।

গল্পে বুঝি

ধানমন্ডির একটা কমিউনিটি সেন্টারে রাজির মেয়ের বিয়ে। গেটে দাঁড়িয়ে আছেন নিরাপত্তারক্ষী হাইসাম, হাতে অতিথির তালিকা। ভেতরে খাবারের হল, আর হলের পেছনে রান্নাঘর, যেখানে বাবুর্চি ফারাবি মাত্র চারজন সহকারী নিয়ে পাঁচশো জনের খাবার বানাচ্ছেন। রাজি জানেন রান্নাঘরই আসল দুর্বল জায়গা: সেখানে একসাথে বেশি লোক ঢুকলে খাবার বানানোই বন্ধ হয়ে যাবে। তাই নিয়ম পরিষ্কার: কেউ সরাসরি রান্নাঘরে যাবে না, সবাই গেট দিয়ে ঢুকবে, আর রান্নাঘরের পেছনের দরজা তালা দেওয়া, চাবি শুধু হাইসামের কাছে।

সন্ধ্যায় তিনটা ঘটনা ঘটল। প্রথমে পাড়ার দুইশো ছেলে একসাথে “দাওয়াত আছে” বলে গেটে ভিড় করল। হাইসাম গেটটা চওড়া করে দুই পাশে আরও দুইজন রক্ষী বসালেন, যাতে ভিড় গেটেই আটকে থাকে, হল পর্যন্ত না পৌঁছায়। তারপর একজন একই লোক বারবার ঘুরে এসে পাঁচবার প্লেট নিল; হাইসাম তার হাতে কালির দাগ দিয়ে দিলেন, আর দাগওয়ালা কেউ তিনবারের বেশি ঢুকতে পারবে না। আর সবচেয়ে চালাক জন, কিন্দি নামের এক প্রতারক, একটা নকল দাওয়াতপত্র নিয়ে এল। কার্ডটা দেখতে আসলের মতোই, কিন্তু হাইসাম কার্ডের কোণে রাজির পরিবারের সিলমোহর আর তারিখ মিলিয়ে দেখলেন: সিল নেই, আর তারিখ গত মাসের।

কিন্দি হাল ছাড়েনি। সে গেটের পাশের টেবিলে বসা ছেলেটাকে, যে অতিথিদের জন্য “আপনার টেবিল নম্বর” লেখা কার্ড বানিয়ে একটা স্তূপে রাখছিল, বলল, “আমার কার্ডে লেখো, পরের সব অতিথি পেছনের টেবিলে বসবে।” ছেলেটা খেয়াল না করে লিখে স্তূপে রেখে দিল, আর পরের বিশজন অতিথি সেই কার্ড নিয়ে ভুল জায়গায় গেল। শেষে রাজি বুঝলেন সমস্যাটা ছেলেটার নিয়মে: সে কারও কথায় কার্ডে যা খুশি লিখছিল, অথচ স্তূপের একটা কার্ড সবাই নেয়।

মিলিয়ে নিই: গেট হলো CDN এজ, রান্নাঘর হলো দুর্বল origin, আর পেছনের তালা দেওয়া দরজা হলো origin লুকানো ও লক করা (শুধু CDN-এর কাছে চাবি)। দুইশো ছেলের ভিড় হলো DDoS, গেট চওড়া করে রক্ষী বাড়ানো হলো CDN-এর বিশাল ক্ষমতা দিয়ে DDoS শোষণ। কালির দাগ আর তিনবারের সীমা হলো রেট লিমিটিং, আর অতিথির তালিকা দেখে সিদ্ধান্ত নেওয়া হলো WAF ও বট ম্যানেজমেন্ট। সিলমোহর আর তারিখ মেলানো হলো signed URL: একটা গোপন সিগনেচার আর মেয়াদ, যা নকল করা যায় না। আর কিন্দির শেষ চালাকি, সবার জন্য রাখা স্তূপের কার্ডে নিজের কথা লিখিয়ে নেওয়া, হলো web cache poisoning: একজন আক্রমণকারী এমন একটা রেসপন্স ক্যাশে বসায় যেটা পরে সবাই পায়। বাস্তবে এজ সিকিউরিটির পুরো কাজটাই এই: খারাপ ট্রাফিক গেটে থামানো, origin-কে আড়ালে রাখা, আর নিশ্চিত করা যে ক্যাশ কখনো একজনের ইচ্ছায় সবার জন্য ভুল জিনিস না রাখে।

স্তরগুলো

Layers of edge defence

প্রতিটা স্তর আলাদা ধরনের আক্রমণ থামায়। একটা স্তর অন্যটার বিকল্প না।

DDoS শোষণ

DDoS মানে অনেক উৎস থেকে একসাথে এত ট্রাফিক যে আপনার সার্ভার বা নেটওয়ার্ক আর আসল ইউজারকে সার্ভ করতে পারে না। দুই ধরনের:

ধরনকী পাঠায়উদাহরণকীভাবে থামে
ভলিউমেট্রিক (L3/L4)বিশাল পরিমাণ প্যাকেট বা বাইটUDP ফ্লাড, SYN ফ্লাড, DNS/NTP amplificationCDN-এর নেটওয়ার্ক ক্ষমতা আর anycast; প্যাকেট এজেই ফেলে দেওয়া
অ্যাপ্লিকেশন (L7)দেখতে আসল HTTP রিকোয়েস্ট, কিন্তু অনেকএকটা ভারী সার্চ পেজে লাখো রিকোয়েস্টWAF নিয়ম, রেট লিমিট, বট চ্যালেঞ্জ, ক্যাশ

Anycast কেন সাহায্য করে: CDN-এর সব PoP একই IP ঘোষণা করে, তাই ইন্টারনেটের রাউটিং প্রতিটা প্যাকেটকে তার কাছের PoP-এ পাঠায়। একটা বটনেট যদি বিশ্বজুড়ে ছড়ানো থাকে, তার ট্রাফিকও শত শত PoP-এ ভাগ হয়ে যায়। কোনো একটা জায়গায় সব আঘাত পড়ে না। আপনার নিজের একটা সার্ভার একটা ডেটা সেন্টারের একটা লিংক দিয়ে যত ট্রাফিক নিতে পারে, CDN তার হাজার গুণ নিতে পারে।

L7 আক্রমণে ক্যাশই সবচেয়ে ভালো অস্ত্র। যে পেজ ক্যাশ থেকে আসে, সেটায় লাখো রিকোয়েস্ট এলেও origin টের পায় না। আক্রমণকারীরা তাই ক্যাশ এড়ানোর চেষ্টা করে: প্রতিটা রিকোয়েস্টে একটা র‍্যান্ডম query string (?x=83jf2), যাতে প্রতিটা MISS হয়। প্রতিরক্ষা: যেসব পাথে query string অর্থহীন সেখানে ক্যাশ কী থেকে query বাদ দিন বা শুধু পরিচিত parameter রাখুন (চ্যাপ্টার ৪), আর অপরিচিত parameter-ওয়ালা রিকোয়েস্টে রেট লিমিট কঠিন করুন।

WAF

WAF (Web Application Firewall) প্রতিটা HTTP রিকোয়েস্ট দেখে নিয়মের সাথে মেলায়: SQL injection-এর প্যাটার্ন, path traversal, পরিচিত দুর্বল প্লাগইনের URL, অস্বাভাবিক হেডার।

  • ম্যানেজড রুলসেট: ভেন্ডর বা OWASP Core Rule Set-এর মতো প্রকল্প নিয়মগুলো রক্ষণাবেক্ষণ করে, নতুন দুর্বলতা বের হলে আপডেট করে।
  • কাস্টম নিয়ম: আপনার অ্যাপের জন্য নির্দিষ্ট। যেমন /admin শুধু অফিসের IP থেকে, বা /api/ শুধু application/json রিকোয়েস্ট।

WAF প্রথমে শুধু লগ মোডে চালান। একটা নতুন নিয়ম আসল ইউজারকে আটকাতে পারে (false positive): একটা ব্লগ পোস্ট যেখানে কেউ SQL কোড লিখেছে, একটা ফর্ম যেখানে কারও নামে অ্যাপস্ট্রফি আছে। এক-দুই সপ্তাহ লগ মোডে রেখে দেখুন কী কী ধরা পড়ছে, false positive-গুলোর জন্য ব্যতিক্রম যোগ করুন, তারপর ব্লক মোডে নিন। আর মনে রাখবেন WAF একটা অতিরিক্ত স্তর, নিরাপদ কোডের বিকল্প না: প্যারামিটারাইজড কুয়েরি তবুও লাগবে।

রেট লিমিটিং

রেট লিমিট বলে: “এই কী থেকে এই সময়ে এতগুলোর বেশি রিকোয়েস্ট না।” আসল প্রশ্ন হলো কী কী দিয়ে গুনবেন:

কীভালো কোথায়সমস্যা
ক্লায়েন্ট IPসহজ, সব জায়গায় কাজ করেমোবাইল অপারেটরের CGNAT আর অফিসের NAT-এ হাজার ইউজার একই IP-তে; IPv6-এ একজনের কাছে অসংখ্য IP
IP + পাথলগইন বা সার্চের মতো নির্দিষ্ট এন্ডপয়েন্টউপরের একই NAT সমস্যা
API কী বা ইউজার আইডিলগইন করা ইউজার বা API ক্লায়েন্টলগইনের আগের পেজে কাজ করে না
সেশন কুকিব্রাউজার ইউজারআক্রমণকারী কুকি ফেলে দিয়ে নতুন নিতে পারে

বাংলাদেশের মতো জায়গায় যেখানে মোবাইল ইন্টারনেট ব্যাপকভাবে CGNAT-এর পেছনে, শুধু IP দিয়ে কঠিন লিমিট আসল ইউজারদের আটকাতে পারে। IPv6-এ পুরো IP-র বদলে একটা prefix (যেমন /64) দিয়ে গোনা ভালো। লগইনের মতো সংবেদনশীল এন্ডপয়েন্টে কঠিন লিমিট, সাধারণ পেজে উদার।

# Illustrative: what a rate-limited client sees
$ curl -sI https://baytalhikma.org/api/search?q=optics
HTTP/2 429
retry-after: 30
content-type: application/json

429 আর Retry-After ঠিকভাবে পাঠান, যাতে ভালো ক্লায়েন্টরা (আপনার মোবাইল অ্যাপ, পার্টনারদের ইন্টিগ্রেশন) বুঝে পিছিয়ে আসে।

বট ম্যানেজমেন্ট

সব বট খারাপ না: সার্চ ইঞ্জিনের ক্রলার, আপটাইম মনিটর, আপনার নিজের ইন্টিগ্রেশন। বট ম্যানেজমেন্টের কাজ হলো আলাদা করা:

  • যাচাইযোগ্য ভালো বট: বড় সার্চ ইঞ্জিনগুলো তাদের ক্রলারের IP রেঞ্জ বা reverse DNS যাচাইয়ের পদ্ধতি প্রকাশ করে। শুধু User-Agent দেখে বিশ্বাস করবেন না, যে কেউ “Googlebot” লিখতে পারে।
  • সন্দেহজনক: ব্রাউজারের মতো দাবি করে কিন্তু JavaScript চালায় না, TLS fingerprint কোনো আসল ব্রাউজারের সাথে মেলে না, মানুষের পক্ষে অসম্ভব গতিতে ক্লিক করে।
  • প্রতিক্রিয়া: সরাসরি ব্লক না করে প্রথমে একটা চ্যালেঞ্জ (অদৃশ্য JavaScript পরীক্ষা বা CAPTCHA), যাতে ভুল হলে মানুষ পার হতে পারে।

এখানে ভারসাম্য জরুরি: কঠিন বট চ্যালেঞ্জ স্ক্রিন রিডার ব্যবহারকারী, ধীর পুরনো ফোন আর গোপনীয়তা-সচেতন ব্রাউজারদের সমস্যায় ফেলে। শুধু সেইসব পাথে কঠিন করুন যেখানে আসল ক্ষতি হয় (লগইন, চেকআউট, ফর্ম জমা)।

Origin লুকানো ও লক করা

CDN-এর সব সুরক্ষা অর্থহীন যদি আক্রমণকারী আপনার origin-এর আসল IP জানে আর সরাসরি সেখানে আঘাত করে। গেট যত মজবুতই হোক, পেছনের দরজা খোলা থাকলে লাভ নেই।

Origin কীভাবে ফাঁস হয়

  • পুরনো DNS রেকর্ড। CDN-এ যাওয়ার আগে আপনার A রেকর্ড সরাসরি origin-এ ছিল। পাসিভ DNS ডেটাবেসগুলো সেই ইতিহাস রেখে দেয়।
  • CDN-এর বাইরে থাকা সাবডোমেইন। mail.baytalhikma.org, ftp., dev., staging. হয়তো একই সার্ভারে, CDN ছাড়া।
  • ইমেইল হেডার। আপনার সার্ভার থেকে সরাসরি পাঠানো ইমেইলের Received: হেডারে সার্ভারের IP থাকে।
  • Certificate Transparency লগ। origin-এর জন্য আলাদা সার্টিফিকেট ইস্যু করলে সেটার হোস্টনেম পাবলিক লগে চলে যায়।
  • অ্যাপ নিজেই। এরর পেজ, ডিবাগ হেডার, বা কোনো ফিচার যেটা origin থেকে বাইরের URL ফেচ করে (তখন টার্গেট সার্ভার origin-এর IP দেখে)।

এই ফাঁসের অনেকগুলো DNS-এর দিক থেকে আসে; বিস্তারিত DNS সিকিউরিটি চ্যাপ্টারে আছে।

Origin লক করা

লুকানো যথেষ্ট না, কারণ IP একদিন ফাঁস হবেই। origin-কে এমনভাবে লক করুন যাতে IP জানলেও কাজ না হয়:

  1. ফায়ারওয়ালে শুধু CDN-এর IP রেঞ্জ। বেশিরভাগ CDN তাদের রেঞ্জ একটা পাবলিক URL-এ প্রকাশ করে; সেটা নিয়মিত সিঙ্ক করুন (রেঞ্জ বদলায়)।
  2. Authenticated origin pull / mTLS। CDN origin-এ কানেক্ট করার সময় একটা ক্লায়েন্ট সার্টিফিকেট দেখায়, origin সেটা ছাড়া কানেকশন নেয় না। IP রেঞ্জের চেয়ে শক্ত, কারণ একই CDN-এর অন্য কাস্টমারও সেই IP থেকে আসতে পারে।
  3. একটা গোপন হেডার। CDN প্রতিটা রিকোয়েস্টে একটা গোপন মান যোগ করে, origin সেটা ছাড়া 403 দেয়। সবচেয়ে সহজ, কিন্তু গোপন মানটা নিয়মিত বদলাতে হয়।
  4. Outbound টানেল। origin কোনো পোর্টই খোলা রাখে না; সে নিজেই CDN-এর দিকে একটা টানেল খোলে। পাবলিক IP-তে কিছুই শোনে না।
# Verify the origin really refuses direct traffic (run from outside your network)
$ curl -sk --resolve baytalhikma.org:443:203.0.113.10 https://baytalhikma.org/ -o /dev/null -w '%{http_code}\n'
000          # connection refused or timed out: good
# 200 here means the origin answers anyone who knows its IP

Signed URL ও টোকেন

কিছু কন্টেন্ট শুধু নির্দিষ্ট ইউজারের জন্য, কিন্তু তবুও CDN থেকে আসা উচিত: কেনা ই-বুক, পেইড কোর্সের ভিডিও, প্রাইভেট ফাইল ডাউনলোড। প্রতিটা রিকোয়েস্টে origin-এ গিয়ে অথ চেক করলে CDN-এর লাভ চলে যায়। সমাধান হলো signed URL: origin একটা URL বানায় যেটায় মেয়াদ আর একটা HMAC সিগনেচার থাকে, আর এজ শুধু সিগনেচার আর মেয়াদ যাচাই করে।

https://baytalhikma.org/books/kitab-al-manazir.pdf?exp=1793001600&sig=Qm9...x2A
// sign.ts — origin side: issue a URL valid for `ttl` seconds
const enc = new TextEncoder();

async function hmac(secret: string, data: string): Promise<string> {
	const key = await crypto.subtle.importKey('raw', enc.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
	const mac = await crypto.subtle.sign('HMAC', key, enc.encode(data));
	return btoa(String.fromCharCode(...new Uint8Array(mac))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

export async function signUrl(path: string, secret: string, ttl: number): Promise<string> {
	const exp = Math.floor(Date.now() / 1000) + ttl;
	const sig = await hmac(secret, `${path}:${exp}`);
	return `${path}?exp=${exp}&sig=${sig}`;
}

// edge side: verify before serving from cache
export async function verify(url: URL, secret: string): Promise<boolean> {
	const exp = Number(url.searchParams.get('exp'));
	const sig = url.searchParams.get('sig') ?? '';
	if (!exp || exp < Date.now() / 1000) return false;
	const expected = await hmac(secret, `${url.pathname}:${exp}`);
	// Constant-time compare so timing does not leak how many characters matched.
	if (expected.length !== sig.length) return false;
	let diff = 0;
	for (let i = 0; i < sig.length; i++) diff |= expected.charCodeAt(i) ^ sig.charCodeAt(i);
	return diff === 0;
}

কয়েকটা নিয়ম:

  • ক্যাশ কী থেকে exp আর sig বাদ দিন। নইলে প্রতিটা ইউজারের প্রতিটা লিংক আলাদা ক্যাশ এন্ট্রি হবে, আর ক্যাশ কখনো HIT হবে না। যাচাই হবে এজে, ক্যাশ হবে শুধু পাথ দিয়ে।
  • মেয়াদ ছোট রাখুন, কাজ অনুযায়ী: একটা ডাউনলোডের জন্য কয়েক মিনিট, একটা ভিডিও সেশনের জন্য কয়েক ঘণ্টা। লিংক শেয়ার হলেও বেশিদিন কাজ করবে না।
  • সিগনেচারে কী কী ঢুকবে ভাবুন। শুধু পাথ আর মেয়াদ সবচেয়ে সাধারণ। ভিডিওর ক্ষেত্রে একটা পুরো ডিরেক্টরির জন্য সাইন করা হয় (যাতে সব সেগমেন্ট কাজ করে)।
  • গোপন কী ঘোরানোর ব্যবস্থা রাখুন: এজ কিছুদিন দুইটা কী-ই মানবে, পুরনো আর নতুন।

Hotlink protection

অন্য সাইট আপনার ছবি বা ভিডিও সরাসরি নিজের পেজে এমবেড করলে ব্যান্ডউইথের বিল আপনার। সহজ প্রতিরক্ষা হলো Referer হেডার দেখা, কিন্তু এটা দুর্বল: অনেক ব্রাউজার বা প্রাইভেসি সেটিং Referer পাঠায় না, আর যে কেউ নকল করতে পারে। খালি Referer allow করুন (নইলে আসল ইউজাররা আটকাবে), আর যেটা সত্যিই সুরক্ষিত রাখতে হবে সেটার জন্য signed URL ব্যবহার করুন।

জিও-ব্লকিং

দেশ অনুযায়ী ব্লক করা আইনি কারণে কখনো দরকার হয় (লাইসেন্সিং, নিষেধাজ্ঞা)। কিন্তু জানুন এর সীমা: দেশ নির্ধারণ হয় IP থেকে, যা VPN দিয়ে সহজেই এড়ানো যায়, আর IP-ভিত্তিক জিও ডেটাবেস কখনো কখনো ভুল। এটা নিরাপত্তার স্তর না, একটা নীতি প্রয়োগের উপায়। আর ব্লক করা রেসপন্স যেন দেশ ভেদে ক্যাশ হয় (দেশ ক্যাশ কীতে, বা no-store), নইলে একটা দেশের 403 সবাই পাবে।

Web cache poisoning

এটা এমন একটা আক্রমণ যেখানে আক্রমণকারী ক্যাশকে ব্যবহার করে একটা খারাপ রেসপন্স সবার কাছে পৌঁছে দেয়। মূল কারণ সবসময় একটা: origin রেসপন্স বানাতে এমন কোনো ইনপুট ব্যবহার করে যেটা ক্যাশ কীতে নেই (একে বলে unkeyed input)।

How an unkeyed header poisons a shared cache

একটা সাধারণ উদাহরণ ধারণার জন্য: অনেক ফ্রেমওয়ার্ক X-Forwarded-Host হেডার বিশ্বাস করে আর সেটা দিয়ে পেজের পুরো URL বানায় (স্ক্রিপ্টের লিংক, canonical URL, রিডাইরেক্ট)। CDN সাধারণত এই হেডারকে ক্যাশ কীতে রাখে না। ফলে একজন আক্রমণকারী একটা MISS-এর সময় হেডারে নিজের ডোমেইন দেয়, origin সেই ডোমেইন দিয়ে স্ক্রিপ্টের লিংক বানায়, CDN রেসপন্সটা /-এর জন্য ক্যাশ করে, আর পরের সব ভিজিটর আক্রমণকারীর সার্ভার থেকে স্ক্রিপ্ট লোড করে।

প্রতিরক্ষা:

  1. origin শুধু সেই হেডার বিশ্বাস করবে যা CDN নিজে সেট করে। এজে ক্লায়েন্টের পাঠানো X-Forwarded-Host, X-Forwarded-Proto, X-Original-URL জাতীয় হেডার মুছে ফেলুন বা নিজের মান দিয়ে ওভাররাইট করুন। ফ্রেমওয়ার্কে হোস্টনেম একটা কনফিগ মান থেকে নিন, রিকোয়েস্ট থেকে না।
  2. যে ইনপুট রেসপন্স বদলায়, সেটা ক্যাশ কীতে রাখুন, বা Vary-তে ঘোষণা করুন। ক্যাশ কী আর রেসপন্সের ইনপুট মিলতে হবে।
  3. এরর রেসপন্স ক্যাশ করার ব্যাপারে সাবধান। একজন আক্রমণকারী একটা অস্বাভাবিক হেডার দিয়ে origin-কে 400 বা 500 দেওয়াতে পারলে, আর CDN সেটা ক্যাশ করলে, পেজটা সবার জন্য ভাঙা দেখাবে (এটাকে cache-poisoned denial of service বলে)। এরর ক্যাশ করলে খুব ছোট TTL দিন।
  4. নিজে পরীক্ষা করুন। স্টেজিং-এ একটা ক্যাশ-বাস্টার query দিয়ে (যাতে আসল ক্যাশ নষ্ট না হয়) বিভিন্ন হেডার পাঠিয়ে দেখুন রেসপন্স বদলায় কিনা। বদলালে, সেই হেডার হয় কীতে যাবে, নয় এজে মুছতে হবে।

Web cache deception

এটা উল্টো দিক থেকে আসে: এখানে আক্রমণকারী CDN-কে দিয়ে একজন ভিকটিমের ব্যক্তিগত পেজ ক্যাশ করিয়ে নেয়, তারপর নিজে সেটা পড়ে।

মূল কারণ হলো CDN আর origin URL-কে আলাদাভাবে বোঝে। ধারণার জন্য: CDN-এর নিয়ম বলে “যা কিছু .css-এ শেষ হয়, সেটা স্ট্যাটিক, ক্যাশ করো।” আর origin-এর ফ্রেমওয়ার্ক একটা URL যেমন /account/settings/x.css পেলে শেষের অংশ উপেক্ষা করে /account/settings পেজটাই দেখায়। আক্রমণকারী একজন লগইন করা ভিকটিমকে এমন একটা লিংকে ক্লিক করায়। origin ভিকটিমের ব্যক্তিগত পেজ দেয়, CDN সেটা .css ভেবে ক্যাশ করে, আর আক্রমণকারী একই URL খুলে ক্যাশ থেকে ভিকটিমের পেজ পায়।

প্রতিরক্ষা:

  1. origin-এ ব্যক্তিগত রেসপন্সে সবসময় Cache-Control: private বা no-store। আর CDN কনফিগ যেন origin-এর এই হেডার মানে, এক্সটেনশন দেখে ওভাররাইট না করে। এটাই সবচেয়ে গুরুত্বপূর্ণ নিয়ম।
  2. এক্সটেনশন নয়, Content-Type দেখে ক্যাশ। CDN যদি ”.css হলে ক্যাশ” না বলে “রেসপন্স text/css হলে ক্যাশ” বলে, তাহলে HTML পেজ ভুলে ক্যাশ হবে না।
  3. origin-এ অপরিচিত পাথে 404। /account/settings/x.css-এর জন্য origin যেন /account/settings না দেখায়। কঠোর রাউটিং।
  4. ক্যাশ নিয়ম শুধু স্ট্যাটিক ডিরেক্টরিতে। “সব .js ক্যাশ করো” না, “শুধু /assets/-এর নিচে ক্যাশ করো”।

ক্যাশ-সংক্রান্ত সবচেয়ে খারাপ বাস্তব ঘটনাগুলো এই দুইটা আক্রমণ না, বরং নিজেদের কনফিগ ভুল: কেউ “পুরো সাইট ক্যাশ করো” নিয়ম চালু করল, আর একজন ইউজারের লগইন করা ড্যাশবোর্ড অন্যদের কাছে যেতে লাগল। নিয়ম একটাই: যে রেসপন্স ইউজার ভেদে আলাদা, সেটা কখনো শেয়ার্ড ক্যাশে যাবে না। নতুন ক্যাশ নিয়ম চালুর আগে দুইটা আলাদা অ্যাকাউন্ট দিয়ে পরীক্ষা করুন (চ্যাপ্টার ৯)।

Request smuggling, সংক্ষেপে

CDN আর origin যদি একটা HTTP/1.1 রিকোয়েস্টের শেষ কোথায় সেটা নিয়ে একমত না হয় (Content-Length আর Transfer-Encoding দুটো থাকলে কাকে মানবে), তাহলে একটা রিকোয়েস্টের ভেতরে আরেকটা লুকিয়ে পাঠানো যায়, যেটা origin অন্য ইউজারের রিকোয়েস্টের অংশ হিসেবে পড়তে পারে। প্রতিরক্ষা মূলত আপনার সফটওয়্যারের কাজ: CDN আর origin সফটওয়্যার আপডেট রাখুন, অস্পষ্ট রিকোয়েস্ট (দুই হেডারই আছে) রিজেক্ট করুন, আর সম্ভব হলে CDN থেকে origin পর্যন্ত HTTP/2 ব্যবহার করুন, যেখানে রিকোয়েস্টের সীমানা প্রোটোকলেই নির্দিষ্ট।

CORS আর ক্যাশ

CORS রেসপন্সে Access-Control-Allow-Origin হেডার রিকোয়েস্টের Origin অনুযায়ী বদলাতে পারে। যদি আপনার API একাধিক সাইটকে allow করে আর প্রতিটা রিকোয়েস্টে সেই সাইটের নাম ফেরত দেয়, তাহলে:

GET /api/books HTTP/2
Origin: https://cordoba.example

HTTP/2 200
access-control-allow-origin: https://cordoba.example
vary: Origin
cache-control: public, max-age=300

vary: Origin ছাড়া CDN প্রথম সাইটের জন্য রেসপন্স ক্যাশ করবে, আর দ্বিতীয় সাইট থেকে আসা রিকোয়েস্ট ভুল access-control-allow-origin পাবে, ব্রাউজার সেটা ব্লক করবে। লক্ষণটা বিভ্রান্তিকর: “CORS মাঝে মাঝে কাজ করে, মাঝে মাঝে করে না”, নির্ভর করে কোন সাইট আগে ক্যাশ ভরিয়েছে তার উপর। যদি API সবার জন্য খোলা হয় (*), তাহলে Vary লাগে না।

ডিবাগিং: এই চ্যাপ্টারের সমস্যাগুলো

লক্ষণনিশ্চিত করার উপায়সমাধান
আক্রমণের সময় origin ডাউন, CDN চালুorigin লগে দেখুন রিকোয়েস্ট CDN-এর IP থেকে আসছে নাকি সরাসরিorigin ফায়ারওয়ালে শুধু CDN রেঞ্জ বা mTLS; origin IP বদলান
র‍্যান্ডম query দিয়ে origin-এ চাপলগে একই পাথে অসংখ্য আলাদা query string দেখুনক্যাশ কী থেকে অপরিচিত parameter বাদ দিন; সেই প্যাটার্নে রেট লিমিট
আসল ইউজাররা 403 পাচ্ছেWAF লগে কোন নিয়ম ম্যাচ করেছে দেখুন (রিকোয়েস্ট আইডি দিয়ে)নিয়মটা লগ মোডে নিন, ব্যতিক্রম যোগ করুন
মোবাইল ইউজাররা গণহারে 429 পাচ্ছেলগে একই IP থেকে কত আলাদা ইউজার আসছে দেখুনIP-র বদলে সেশন বা ইউজার আইডি দিয়ে লিমিট; লিমিট বাড়ান
সরাসরি origin IP-তে সাইট খোলেcurl --resolve host:443:ORIGIN_IP https://host/ বাইরে থেকেফায়ারওয়াল লক, authenticated origin pull
Signed URL সবসময় 403সার্ভার আর এজের ঘড়ি মেলে কিনা দেখুন (date -u), সাইন করা স্ট্রিং আর যাচাইয়ের স্ট্রিং এক কিনাNTP চালু করুন; পাথ এনকোডিং দুই জায়গায় একই রাখুন
Signed URL-এ hit ratio শূন্যের কাছেক্যাশ কীতে sig আর exp আছে কিনা দেখুনক্যাশ কী থেকে এই parameter বাদ দিন
পেজে অচেনা ডোমেইনের স্ক্রিপ্ট দেখা যাচ্ছেক্যাশ-বাস্টার দিয়ে origin-এ সরাসরি একই পেজ চেয়ে তুলনা করুন; এজ লগে ঐ সময়ের রিকোয়েস্ট হেডার দেখুনপার্জ করুন; এজে ফরওয়ার্ড হেডার মুছুন; হোস্টনেম কনফিগ থেকে নিন
একজনের অ্যাকাউন্ট পেজ অন্যজন দেখছেcurl -sI দিয়ে ঐ পাথের cache-control আর ক্যাশ স্ট্যাটাস দেখুনসাথে সাথে পার্জ ও বাইপাস; private, no-store; এক্সটেনশন-ভিত্তিক ক্যাশ নিয়ম সরান
CORS মাঝে মাঝে ব্যর্থদুই আলাদা Origin দিয়ে রিকোয়েস্ট করে access-control-allow-origin তুলনা করুনVary: Origin যোগ করুন, পার্জ করুন
জিও-ব্লকের 403 ভুল দেশেও আসছেরেসপন্সে age আর ক্যাশ স্ট্যাটাস দেখুনব্লক রেসপন্স no-store, বা দেশকে ক্যাশ কীতে নিন

মূল শিক্ষা

  1. এজ সিকিউরিটি স্তরে স্তরে: DDoS শোষণ, WAF ও বট নিয়ম, রেট লিমিট, ক্যাশ, তারপর লক করা origin। একটা অন্যটার বিকল্প না।
  2. Anycast আর বিশাল নেটওয়ার্ক ভলিউমেট্রিক আক্রমণ ছড়িয়ে দেয়; L7 আক্রমণে ক্যাশই সবচেয়ে ভালো ঢাল, তাই ক্যাশ এড়ানোর কৌশল বন্ধ করুন।
  3. WAF প্রথমে লগ মোডে। False positive আসল ইউজারকে আটকায়।
  4. রেট লিমিটের কী বেছে নিন সাবধানে। CGNAT-এর দেশে শুধু IP দিয়ে কঠিন লিমিট আসল ইউজারদের শাস্তি দেয়।
  5. Origin লুকানো যথেষ্ট না, লক করুন। IP একদিন ফাঁস হবেই।
  6. Signed URL ব্যক্তিগত কন্টেন্টকে CDN থেকে সার্ভ করতে দেয়; ছোট মেয়াদ, constant-time যাচাই, আর ক্যাশ কী থেকে সিগনেচার বাদ।
  7. Cache poisoning হয় যখন রেসপন্স বদলানো ইনপুট ক্যাশ কীতে নেই। ইনপুট আর কী মেলান; ক্লায়েন্টের ফরওয়ার্ড হেডার এজে মুছুন।
  8. Cache deception হয় যখন CDN আর origin URL আলাদাভাবে বোঝে। ব্যক্তিগত রেসপন্সে private, Content-Type দেখে ক্যাশ, কঠোর রাউটিং।
  9. ইউজার ভেদে আলাদা রেসপন্স কখনো শেয়ার্ড ক্যাশে না, আর ভেরিয়েবল CORS হেডারের সাথে Vary: Origin।