Web Cache Deception چیست؟ چگونه اطلاعات کاربران از طریق Cache افشا میشود؟
Web Cache Deception زمانی ایجاد میشود که Cache یک Response شخصی و داینامیک را به دلیل تفسیر اشتباه URL، بهعنوان محتوای عمومی ذخیره کند و آن را در اختیار کاربران دیگر قرار دهد. این ضعف معمولاً از اختلاف میان Path Mapping، URL Normalization یا Cache Rule در CDN و Origin Server ناشی میشود و میتواند اطلاعات حساب، سفارشها یا دادههای شخصی کاربران را افشا کند.
Web Cache Deception یا «فریب کش وب» نوعی آسیبپذیری امنیتی است که باعث میشود محتوای خصوصی و داینامیک یک کاربر به اشتباه توسط یک Shared Cache مانند CDN یا Reverse Proxy بهعنوان محتوای عمومی و استاتیک ذخیره شود. مهاجم سپس میتواند همان URL را بدون Session قربانی درخواست کند و نسخه Cacheشده اطلاعات خصوصی او را دریافت کند.
ریشه Web Cache Deception معمولاً اختلاف میان نحوه تفسیر URL در Origin Server و سیستم Cache است. برای مثال ممکن است Application یک URL ظاهراً مربوط به فایل .css یا .jpg را همچنان به صفحه Profile کاربر نگاشت کند، در حالی که CDN فقط پسوند فایل را میبیند و Response را استاتیک تصور میکند. مهمترین راهکار دفاعی این است که صفحات شخصی و Dynamic با Cache-Control: no-store, private از Shared Cache خارج شوند، Cache Ruleها بر اساس مسیرهای صریح و قابل اعتماد طراحی شوند و Cache و Origin یک URL را به شکل یکسان Parse و Normalize کنند.
Web Cache چیست و چرا وجود دارد؟
بسیاری از وبسایتها برای افزایش سرعت و کاهش فشار روی Server از Cache استفاده میکنند.
فرض کنید هزاران کاربر همزمان یک فایل CSS یا تصویر لوگو را درخواست کنند.
بدون Cache:
User
↓
Origin Server
↓
Read file / generate response
↓
User
این فرایند برای هر User دوباره تکرار میشود.
اما با Cache:
User A
↓
Cache MISS
↓
Origin
↓
Response stored in Cache
User B
↓
Cache HIT
↓
Cached Response
RFC 9111 یک HTTP Cache را محلی برای ذخیره Response Messageها و مجموعهای از مکانیزمها برای Storage، Retrieval و Removal آنها تعریف میکند. هدف Cache کاهش زمان پاسخ و مصرف منابع از طریق استفاده مجدد از Response برای Requestهای معادل است.
این قابلیت برای فایلهایی مانند:
CSS،
JavaScript،
فونت،
تصاویر،
Video Segment،
و فایلهای عمومی
بسیار مفید است.
اما همان قابلیتی که Performance را افزایش میدهد میتواند در صورت پیکربندی اشتباه به یک خطر امنیتی تبدیل شود.
Shared Cache و Private Cache
Cache را میتوان به دو گروه مهم تقسیم کرد.
Private Cache معمولاً فقط برای یک User است؛ Browser Cache نمونه شناختهشده آن است.
Shared Cache میان چند User مشترک است.
برای مثال:
CDN،
Reverse Proxy،
Varnish،
Nginx Cache،
Proxyهای سازمانی.
RFC 9111 تصریح میکند Shared Cache پاسخها را برای استفاده بیش از یک User نگهداری میکند. همین ویژگی باعث میشود Cache کردن اشتباه اطلاعات خصوصی بسیار خطرناک باشد.
فرض کنید اطلاعات حساب User A وارد CDN شود.
اگر همان Response برای افراد دیگر قابل بازیابی باشد، Cache عملاً از یک Performance Layer به محل نشت اطلاعات تبدیل شده است.
Web Cache Deception چیست؟
PortSwigger، Web Cache Deception را ضعف ناشی از اختلاف میان نحوه پردازش Request توسط Cache و Origin Server تعریف میکند.
در این حمله مهاجم قربانی را به باز کردن URL خاصی هدایت میکند.
Origin Server آن URL را به یک Resource شخصی یا Dynamic نگاشت میکند.
اما Cache URL را شبیه یک Resource عمومی و Static میبیند و Response را ذخیره میکند.
پس از آن مهاجم همان URL را درخواست میکند و نسخه Cacheشده Response قربانی را دریافت میکند.
مدل کلی:
Attacker
↓
Creates deceptive URL
↓
Victim opens URL while authenticated
↓
CDN / Cache
↓
Origin returns private content
↓
Cache mistakenly stores it
↓
Attacker requests same URL
↓
Cached private response exposed
نکته کلیدی این است که مهاجم الزاماً Session قربانی را در اختیار ندارد.
قربانی خودش با Session معتبر باعث تولید Response خصوصی میشود.
Cache همان Response را به اشتباه عمومی میکند.
چرا نام آن Cache Deception است؟
واژه Deception یا فریب به این موضوع اشاره دارد که Cache درباره ماهیت Resource فریب میخورد.
Origin میگوید:
این درخواست مربوط به اطلاعات شخصی کاربر است.
اما Cache تصور میکند:
این URL شبیه یک فایل استاتیک است،
پس میتوانم Response را عمومی ذخیره کنم.
این اختلاف دید اساس آسیبپذیری است.
به بیان ساده:
Origin sees dynamic content.
Cache sees static content.
وقتی این دو Component درباره ماهیت Resource توافق ندارند، مرز امنیتی Cache شکسته میشود. 
Web Cache Deception چگونه اطلاعات کاربران را افشا میکند؟
فرض کنید User وارد حساب خود شده و مسیر زیر اطلاعات شخصی او را نمایش میدهد:
/account/profile
این Response ممکن است شامل:
نام،
Email،
شماره تلفن،
اطلاعات سفارش،
تنظیمات حساب
باشد.
در حالت طبیعی این صفحه نباید Shared Cache شود.
اما Application ممکن است Routeهای اضافه را نادیده بگیرد.
برای مثال ممکن است مسیر مفهومی زیر نیز همان Profile را برگرداند:
/account/profile/something
در حالی که CDN تصمیم بگیرد هر URL که ظاهری شبیه یک فایل Static دارد Cache شود.
در چنین شرایطی یک URL غیرعادی ممکن است از دید Application هنوز Profile باشد ولی Cache آن را Static Resource تلقی کند.
اگر قربانی URL مذکور را باز کند:
Origin Response خصوصی او را تولید میکند.
CDN Response را ذخیره میکند.
مهاجم بعداً همان URL را بدون Authentication درخواست میکند.
اگر Cache HIT رخ دهد، Response قربانی بدون رسیدن Request به Origin برگردانده میشود.
PortSwigger این اختلاف در Path Mapping را یکی از اصلیترین مدلهای Web Cache Deception معرفی میکند.
چرا Authentication جلوی این حمله را نمیگیرد؟
این نکته بسیار مهم است.
ممکن است Endpoint کاملاً Authentication داشته باشد.
Origin Server میگوید:
User authenticated?
Yes.
Return profile.
پس از دید Backend همهچیز درست است.
مشکل بعد از آن اتفاق میافتد.
Shared Cache Response را ذخیره میکند.
Request بعدی مهاجم ممکن است اصلاً به Application نرسد.
مدل:
Attacker request
↓
Shared Cache HIT
↓
Private response returned
در این حالت Authorization Backend فرصت اجرا ندارد.
به همین دلیل Cache باید خودش بداند چه Responseهایی نباید ذخیره یا بین Userها Share شوند.
Cache Rule چیست؟
Cache Rule مشخص میکند چه Resourceهایی قابل Cache هستند و برای چه مدتی نگهداری شوند.
PortSwigger توضیح میدهد Cache Ruleها معمولاً برای Static Resourceها طراحی میشوند و میتوانند بر اساس Extension، Directory یا File Name عمل کنند.
مثلاً:
*.css
*.js
*.jpg
*.png
ممکن است Cacheable باشند.
یا:
/static/*
/assets/*
/images/*
Cache شوند.
این Ruleها ذاتاً اشتباه نیستند.
مشکل زمانی ایجاد میشود که یک Dynamic Endpoint بتواند URLی تولید کند که با Rule استاتیک Match شود.
Static Extension Cache Rule چیست؟
یکی از مدلهای اصلی Web Cache Deception زمانی اتفاق میافتد که CDN براساس پسوند URL تصمیم به Cache کردن بگیرد.
برای مثال:
.css
.js
.jpg
.ico
ممکن است بهصورت پیشفرض Static در نظر گرفته شوند.
PortSwigger میگوید Cache Ruleهای مبتنی بر Extension در بسیاری از CDNها متداولاند و اختلاف میان Path Mapping در Cache و Origin میتواند باعث شود یک Dynamic Response زیر URL دارای Static Extension ذخیره شود.
مشکل مفهومی:
URL appears static to Cache
↓
Origin still returns dynamic account data
↓
Response gets cached
بنابراین Extension بهتنهایی نباید دلیل کافی برای عمومی بودن Response باشد. 
Path Mapping چیست؟
Path Mapping فرایندی است که مشخص میکند یک URL به چه Resource یا Handlerی در Server نگاشت شود.
در معماری سنتی ممکن است:
/images/logo.png
مستقیماً به فایلی روی File System اشاره کند.
اما Frameworkهای مدرن از Routing انتزاعی استفاده میکنند.
مثلاً:
/users/123/profile
ممکن است هیچ فایل فیزیکی با این نام وجود نداشته باشد.
Framework مسیر را به Controller یا Handler تبدیل میکند.
PortSwigger توضیح میدهد تفاوت Path Mapping در Cache و Origin میتواند مستقیماً Web Cache Deception ایجاد کند.
RESTful Routing چگونه ریسک ایجاد میکند؟
در RESTful Applicationها بخشهای مختلف Path ممکن است Parameter محسوب شوند.
مثلاً:
/users/123/profile
میتواند Resource Profile User 123 باشد.
برخی Routerها ممکن است Segment اضافی را:
نادیده بگیرند،
به Parameter تبدیل کنند،
یا همچنان Route اصلی را Match کنند.
Cache ممکن است رفتار متفاوتی داشته باشد.
مثلاً Origin بگوید:
/users/123/profile/extra
=
profile endpoint
اما CDN Path کامل را یک Resource مستقل تصور کند.
این اختلاف Parse مهمتر از ظاهر URL است. 
Delimiter چیست؟
Delimiter کاراکتری است که بخشهای URL را از یکدیگر جدا میکند.
مثلاً ? معمولاً Path را از Query String جدا میکند.
اما Frameworkها ممکن است درباره بعضی Characterها رفتار متفاوتی داشته باشند.
برای نمونه بعضی Frameworkها کاراکتر ; را بهعنوان بخش خاصی از Routing یا Matrix Parameter تفسیر میکنند.
PortSwigger نشان میدهد اختلاف در تفسیر Delimiter میان Cache و Origin میتواند باعث Web Cache Deception شود.
مدل مفهومی:
Cache sees:
/profile;something.css
Origin sees:
/profile
اگر Origin اطلاعات Profile را برگرداند ولی Cache URL را فایل CSS تصور کند، Response خصوصی ممکن است Cache شود.
چرا اختلاف Delimiter مهم است؟
URL فقط یک String ساده نیست.
این String توسط Componentهای مختلف پردازش میشود:
Browser،
CDN،
WAF،
Reverse Proxy،
Web Server،
Framework،
Router.
اگر هر Layer مرزهای URL را متفاوت درک کند، یک URL واحد ممکن است چند معنی داشته باشد.
مثلاً:
Cache interpretation ≠ Origin interpretation
این Interpretation Gap یکی از مهمترین Root Causeهای Web Cache Deception است.
URL Encoding و Web Cache Deception
URLها ممکن است شامل Characterهای Encodeشده باشند.
برای مثال Character خاصی میتواند با Percent-Encoding ارسال شود.
Cache ممکن است مقدار Encodeشده را بدون Decode بررسی کند.
Origin ممکن است ابتدا Decode کند و سپس Routing انجام دهد.
یا برعکس.
PortSwigger این موضوع را Delimiter Decoding Discrepancy مینامد و توضیح میدهد اختلاف در Decode کردن Characterها میتواند Cache و Origin را به Interpretationهای متفاوت از Path برساند.
از دید دفاعی مهمترین نکته این است:
Normalization order must be consistent.
همه Componentها باید درباره URL نهایی تا حد امکان برداشت هماهنگی داشته باشند.
URL Normalization چیست؟
Normalization یعنی تبدیل نمایشهای مختلف یک Path به Representation استاندارد.
این کار ممکن است شامل:
Decode کردن بعضی Characterها،
پردازش Dot Segmentها،
حذف Pathهای اضافی،
یا Normalize کردن Slashها
باشد.
PortSwigger میگوید اختلاف در URL Normalization بین Cache و Origin میتواند Web Cache Deception ایجاد کند.
برای مثال Cache ممکن است ابتدا Rule را بررسی کند و سپس URL را Normalize کند.
Origin ممکن است اول Normalize کند.
Order Operationها میتواند نتیجه را تغییر دهد.
Static Directory Cache Rule
بعضی Cacheها بهجای Extension، Directory خاص را Cache میکنند.
برای مثال:
/static/
/assets/
/images/
/scripts/
فرض بر این است که تمام Content این Directoryها Public و Static است.
PortSwigger اشاره میکند Cache Ruleهای مبتنی بر Directory نیز در صورت اختلاف Path Normalization میان Cache و Origin میتوانند در Web Cache Deception نقش داشته باشند.
قاعده امن:
Directory که بهعنوان Static تعریف شده باید واقعاً فقط Static Content ارائه کند.
نباید Router بتواند Dynamic Account Endpoint را تحت Representationی وارد همان Namespace کند.
File Name Cache Rule
بعضی File Nameها تقریباً در همه وبسایتها عمومیاند.
مثلاً:
robots.txt
favicon.ico
Cache ممکن است این نامها را همیشه قابل Cache در نظر بگیرد.
PortSwigger توضیح میدهد File Name Cache Rule نیز اگر با Normalization متفاوت Cache و Origin ترکیب شود میتواند زمینه Deception ایجاد کند.
پس حتی Rule بسیار محدود نیز باید با Routing واقعی Application سازگار باشد.
Web Cache Deception چه اطلاعاتی را میتواند افشا کند؟
Impact کاملاً به Endpoint قربانی بستگی دارد.
اگر Dynamic Response فقط نام User را داشته باشد، نشت محدودتر است.
اما بعضی صفحات Account شامل اطلاعات بسیار حساس هستند:
Email و شماره تلفن،
آدرس،
Order History،
Invoice،
Subscription،
Profile Data،
Tokenهای موقت،
CSRF Token،
Internal ID،
Preferences،
اطلاعات مالی محدود،
یا API Responseهای شخصی.
بنابراین Severity باید براساس Data واقعی ارزیابی شود.
آیا Password هم ممکن است Cache شود؟
Application امن نباید Password خام را در Response قرار دهد.
Web Cache Deception Password را جادویی از Database استخراج نمیکند.
فقط Dataای را افشا میکند که Origin در Response قربانی برمیگرداند.
اگر صفحه Profile Password را نشان نمیدهد، Cache نیز Passwordی برای ذخیره ندارد.
این تفاوت برای ارزیابی Impact مهم است.
نباید Finding را با ادعای غیرواقعی بزرگتر کرد.
CSRF Token و Web Cache Deception
برخی HTML Responseها CSRF Token دارند.
اگر Page خصوصی Cache شود، ممکن است Token نیز داخل Response ذخیره شود.
اما افشای Token لزوماً به معنی Exploit کامل CSRF نیست.
باید بررسی شود Token:
به User Bind شده؟
یکبارمصرف است؟
Session مستقل دارد؟
چه Actionهایی را محافظت میکند؟
Security Assessment باید Chain واقعی را بررسی کند.
با این حال CSRF Token نمونه خوبی از Dataای است که نباید در Shared Cache منتشر شود.
Web Cache Deception و API
این ضعف فقط مربوط به HTML نیست.
یک API Endpoint ممکن است چنین Responseای داشته باشد:
{
"name": "User",
"email": "...",
"orders": [...]
}
اگر CDN به اشتباه یک URL تغییرشکلیافته را Static تصور کند، JSON شخصی نیز میتواند Cache شود.
API Gateway و CDN باید بدانند کدام Routeها:
Public،
User-Specific،
Authenticated
هستند.
Method GET بهتنهایی به معنی Public بودن Response نیست.
GET امن است ولی لزوماً Public نیست
در HTTP، GET معمولاً Safe Method محسوب میشود؛ یعنی هدف آن تغییر State نیست.
اما Safe بودن با Public بودن متفاوت است.
این URL:
GET /account
میتواند کاملاً Sensitive باشد.
Cache Ruleهایی که میگویند:
تمام GETها Cache شوند
برای بسیاری از Applicationها خطرناکاند.
Cache Eligibility باید بر اساس ماهیت Resource مشخص شود، نه فقط Method.
نقش Cache-Control
یکی از مهمترین Defenseها Header استاندارد:
Cache-Control
است.
برای محتوای خصوصی و داینامیک، Directiveهای مناسب میتوانند Shared Cache را از ذخیره Response منع کنند.
PortSwigger در توصیههای دفاعی Web Cache Deception مشخصاً توصیه میکند Dynamic Resourceها با no-store و private علامتگذاری شوند. همچنین CDN نباید Cache Ruleهایی داشته باشد که این Headerها را Override کنند.
برای صفحات بسیار حساس:
Cache-Control: no-store, private
یک Policy مهم است.
no-store چه میکند؟
no-store به Cache میگوید Response نباید ذخیره شود.
RFC 9111 درباره Storage و Reuse Responseها قواعد Cache-Control را تعریف میکند و در بخش Security نیز درباره خطر Cache شدن اطلاعات حساس هشدار میدهد.
این Directive مخصوصاً برای:
Account Page،
Dashboard،
Password Reset،
Private API Response،
و اطلاعات مالی
مهم است.
private چه میکند؟
private یعنی Response نباید در Shared Cache ذخیره شود.
Browser Private Cache بسته به Policy ممکن است رفتار متفاوتی داشته باشد، اما CDN و Proxy مشترک نباید Response را بین کاربران به اشتراک بگذارند.
این دقیقاً همان چیزی است که در مقابل Web Cache Deception اهمیت دارد.
هدف:
Private user response
≠
Shared cached response
است.
آیا فقط Cache-Control کافی است؟
نه.
در یک Architecture استاندارد، Cache-Control باید کنترل اصلی باشد.
اما بعضی CDN Ruleها میتوانند Origin Cache Policy را Override کنند.
برای مثال Configurationهایی مانند:
Cache Everything،
Edge TTL اجباری،
یا Custom Cache Rule
ممکن است Behavior را تغییر دهند.
Cloudflare نیز در مستندات Cache Deception Armor هشدار میدهد که Origin Cache-Control یا بعضی Edge Cache TTL Ruleها میتوانند روی رفتار این Protection اثر بگذارند.
بنابراین باید هم Origin و هم CDN بررسی شوند.
Web Cache Deception در CDN
CDNها برای Cache کردن Static Asset بسیار مفیدند.
اما Rule عمومی مثل:
cache anything ending in .jpg
فقط زمانی امن است که URL دارای .jpg واقعاً نتواند Dynamic Sensitive Response برگرداند.
Cloudflare در توضیح Web Cache Deception سناریویی را مطرح میکند که Origin یک URL ظاهراً مربوط به Static Asset را همچنان به Dynamic Page نگاشت میکند و CDN به دلیل Extension پاسخ را Cache میکند.
این تعریف دقیقاً نشان میدهد مشکل فقط CDN نیست.
مشکل ناسازگاری:
CDN caching rule
+
Origin routing behavior
است.
Cache Deception Armor چیست؟
Cloudflare قابلیتی به نام Cache Deception Armor ارائه میدهد.
این قابلیت بررسی میکند Extension URL با Content-Type Response مطابقت داشته باشد.
مثلاً اگر URL با .jpg تمام شود اما Origin:
Content-Type: text/html
برگرداند، این mismatch میتواند نشانه Web Cache Deception باشد و Cache از ذخیره Response جلوگیری کند.
مدل:
Request path → .jpg
Origin response → text/html
Mismatch
↓
Do not cache
این کنترل میتواند Defense in Depth بسیار مفیدی باشد.
آیا Cache Deception Armor کافی است؟
خیر.
خود Cloudflare اشاره میکند رفتار Protection به سایر Cache Policyها نیز وابسته است و بعضی Ruleها ممکن است بر Cache Eligibility اثر بگذارند.
همچنین همه CDNها Feature یکسانی ندارند.
Root Defense همچنان:
Cache-Control صحیح،
Routing صریح،
عدم Cache صفحات خصوصی،
و هماهنگی Origin/Cache
است.
Content-Type چه نقشی دارد؟
Content-Type به Client میگوید Response چه نوع Mediaای دارد.
مثلاً:
text/html
image/jpeg
text/css
application/javascript
اگر URL ظاهراً:
photo.jpg
باشد ولی Origin HTML Profile برگرداند، mismatch واضحی وجود دارد.
Cacheهای هوشمند میتوانند از این Signal برای جلوگیری از Deception استفاده کنند.
اما Content-Type باید خود Origin نیز بهدرستی تنظیم شود.
MIME Type اشتباه میتواند Security Detection را ضعیف کند. 
تفاوت Web Cache Deception با Web Cache Poisoning
این دو آسیبپذیری نام مشابهی دارند ولی هدف آنها کاملاً متفاوت است.
در Web Cache Poisoning مهاجم Response دستکاریشده یا مخرب را وارد Cache میکند تا کاربران دیگر آن را دریافت کنند.
در Web Cache Deception، مهاجم قربانی را وادار میکند Response خصوصی خودش را وارد Cache کند و سپس مهاجم همان Response را بازیابی میکند.
PortSwigger نیز این تفکیک را صریح بیان میکند.
| ویژگی | Web Cache Deception | Web Cache Poisoning |
|---|---|---|
| هدف | افشای محتوای خصوصی قربانی | توزیع محتوای دستکاریشده |
| چه کسی Cache را پر میکند؟ | قربانی احراز هویتشده | مهاجم |
| چه چیزی Cache میشود؟ | Response واقعی و خصوصی | Response دستکاریشده |
| چه کسی Benefit میگیرد؟ | مهاجم Response قربانی را میخواند | کاربران Response مهاجم را دریافت میکنند |
| اثر اصلی | Confidentiality | Integrity و گاهی Availability |
| Root Cause رایج | اختلاف Cache Rule و Path Parsing | Unkeyed Input و Cache Key ناقص |
این تفاوت باید در Report امنیتی رعایت شود.
Web Cache Deception با Cache Poisoning Chain میشود؟
از نظر تئوری ممکن است یک Application چند ضعف مرتبط با Cache داشته باشد.
اما Findingها باید جدا تحلیل شوند.
اگر اطلاعات خصوصی Cache میشود:
Deception مطرح است.
اگر Attacker Content خاصی را برای دیگران وارد Cache میکند:
Poisoning مطرح است.
استفاده از عنوان درست به Developer کمک میکند Root Cause واقعی را Fix کند.
Web Cache Deception و Path Traversal
برخی مدلهای Cache Deception از اختلاف URL Normalization و Path Resolution استفاده میکنند.
این رفتار ممکن است از نظر ساختار شبیه Path Traversal باشد، اما هدف متفاوت است.
در Path Traversal مهاجم سعی میکند Resource خارج از Directory موردنظر را مستقیماً از File System بخواند.
در Cache Deception، Path غیرعادی برای ایجاد اختلاف Interpretation میان Cache و Origin استفاده میشود.
پس:
Path Traversal ≠ Web Cache Deception
هرچند Path Normalization یکی از نقاط مشترک است.
Web Cache Deception و Authorization
مشکل اصلی Authorization نیست.
ممکن است Origin Authorization کاملاً صحیح داشته باشد.
قربانی باید Login باشد تا Response تولید شود.
مشکل این است که Response پس از Authorization وارد Shared Cache شده و در Request بعدی بدون Authorization بازگردانده میشود.
بنابراین Security Architecture باید علاوه بر:
Can this user access the endpoint?
بپرسد:
Can this response be shared with another user?
این سؤال اغلب در Design فراموش میشود. 
Web Cache Deception در WordPress
WordPress میتواند پشت چند Cache Layer قرار داشته باشد:
CDN،
Nginx FastCGI Cache،
Hosting Cache،
Page Cache Plugin،
Reverse Proxy.
Core WordPress برای بعضی Contextهای حساس Headerهای No-Cache ارسال میکند.
مستندات رسمی nocache_headers() میگویند این Function Headerهای لازم برای جلوگیری از Cache شدن را ارسال میکند.
در نسخههای فعلی WordPress، wp_get_nocache_headers() مقدار Cache-Control را شامل:
no-cache
must-revalidate
max-age=0
no-store
private
میسازد.
این رفتار برای صفحات Private اهمیت زیادی دارد.
WordPress برای کاربران Loginشده چه میکند؟
در WP::send_headers()، WordPress برای کاربر Loginشده Headerهای No-Cache را به Response اضافه میکند.
این یک Defense مهم است.
اما امنیت نهایی به این بستگی دارد که CDN، Reverse Proxy و Cache Plugin واقعاً این Headerها را رعایت کنند.
اگر یک Rule خارجی بگوید:
Cache Everything
و Origin Policy را Override کند، Protection Application ممکن است بیاثر شود.
Pluginهای Cache وردپرس
Page Cache Pluginها معمولاً URL عمومی Site را Cache میکنند.
اما باید برای مواردی مانند:
Dashboard،
Member Area،
Custom Account Page،
Formهای شخصی،
Private Download Page،
REST Endpointهای احراز هویتشده
Exception داشته باشند.
مشکل اصلی Custom Featureها هستند.
Cache Plugin ممکن است بداند:
/wp-admin/
نباید Cache شود.
اما نمیداند Plugin اختصاصی شما:
/customer-center/
را به Account Dashboard تبدیل کرده است.
هر Custom Route باید Cache Policy صریح داشته باشد.
WordPress REST API و Cache Deception
REST API میتواند اطلاعات عمومی یا خصوصی برگرداند.
WordPress در REST Server برای Requestهای Loginشده امکان ارسال No-Cache Header دارد و Hook rest_send_nocache_headers این رفتار را کنترل میکند.
اما اگر CDN کل /wp-json/ را بهصورت Aggressive Cache تنظیم کند، Configuration خارجی میتواند مشکل ایجاد کند.
بنابراین:
REST GET
نباید خودکار:
Public cacheable
فرض شود.
WooCommerce و Web Cache Deception
WooCommerce دارای صفحات کاملاً وابسته به Session است.
نمونهها:
Cart،
Checkout،
My Account،
Order Details.
این صفحات نباید مانند Blog Post عمومی Cache شوند.
اگر CDN یا Plugin Cache بر اساس Extension یا Path اشتباه Response شخصی را ذخیره کند، ممکن است اطلاعات:
Order،
Address،
Account Data،
Cart
افشا شود.
برای WooCommerce باید Cache Exclusionها و Session Cookie Ruleها بهصورت End-to-End بررسی شوند.
صفحات Membership و LMS
سایتهای Membership، Course و Subscription نیز حساساند.
صفحهای مانند:
/my-courses
ممکن است لیست دورههای خریداریشده را نمایش دهد.
اگر Cache URL غیرمعمول را Static تلقی کند ولی WordPress همان Template خصوصی را Render کند، Response میتواند در معرض Deception قرار گیرد.
هر Route شخصی باید Explicitly Non-Cacheable باشد.
دانلود فایل خصوصی
بعضی سایتها Download URLهای خصوصی تولید میکنند.
مثلاً PDF یا Invoice فقط برای User خاص قابل مشاهده است.
اگر Authorization در Dynamic Handler انجام شود ولی Cache URL را Static File تصور کند، Response ممکن است Shared شود.
این مورد اهمیت زیادی دارد زیرا File Extension ذاتاً شبیه Resource قابل Cache است.
بهتر است Private Downloadها:
Cache-Control مناسب،
Authorization در Endpoint،
و در صورت نیاز Signed URL محدود
داشته باشند.
Signed URL آیا مشکل را حل میکند؟
Signed URL میتواند Access را محدود کند.
اما Cache Policy همچنان مهم است.
اگر Response خصوصی باید فقط برای یک User قابل استفاده باشد، Shared Cache نباید Signed Response را بدون در نظر گرفتن Signature یا Policy مربوط به آن بین کاربران Share کند.
Security Featureها مستقل نیستند.
Authorization URL و Cache Key باید با یکدیگر هماهنگ باشند.
Cache Key در Web Cache Deception چه نقشی دارد؟
Cache Key تعیین میکند چه Requestهایی معادل محسوب شوند.
معمولاً شامل مواردی مانند:
Host،
Path،
Query String
است.
اما Web Cache Deception فقط Cache Key Manipulation نیست.
اغلب مشکل اصلی این است که Cache Rule براساس Path تصمیم میگیرد چیزی را Cache کند که اصلاً نباید Cache شود.
پس تفاوت مهم:
در Poisoning تمرکز اغلب روی Cache Key است.
در Deception تمرکز بیشتر روی Cache Eligibility و Path Interpretation است.
Cache Eligibility چیست؟
Cache Eligibility یعنی Cache تصمیم بگیرد Response اصلاً اجازه ذخیره شدن دارد یا نه.
یک Page میتواند Cache Key کاملاً منحصربهفرد داشته باشد اما همچنان نباید در Shared Cache ذخیره شود.
برای مثال:
/account/user-123
حتی اگر Key دقیق باشد، اگر URL بعداً توسط شخص دیگری قابل Request باشد و Authentication بخشی از Key نباشد، Data Exposure ممکن است ایجاد شود.
پس سؤال اول:
Should this response be cached?
است.
نه فقط:
What should its cache key be?

مهمترین روش جلوگیری از Web Cache Deception
بهترین استراتژی «Default Deny» برای Cache است.
یعنی فقط Resourceهایی Cache شوند که تیم مطمئن است عمومی و Static هستند.
PortSwigger نیز توصیه میکند Dynamic Resourceها با no-store و private مشخص شوند، CDN این Headerها را Override نکند و اختلاف Path Interpretation بین Cache و Origin حذف شود.
مدل:
Unknown resource
↓
Do not shared-cache
و:
Explicitly public static resource
↓
Cache allowed
از مدل:
Cache everything unless blocked
امنتر است.
پسوند فایل نباید تنها معیار Cache باشد
Rule:
*.css → cache
میتواند بسیار سریع باشد.
اما اگر Origin هر Path ختمشونده به .css را الزاماً فایل CSS نمیداند، Rule خطرناک میشود.
روش امنتر:
Cache فقط از Static Directory مشخص انجام شود:
/assets/css/*
و Origin نیز تضمین کند این Directory هرگز Dynamic Route نیست.
حتی بهتر:
File Extension و Content-Type نیز هماهنگ باشند.
Static Namespace واقعی بسازید
یکی از بهترین معماریها جداسازی صریح Static و Dynamic Content است.
مثلاً:
/static/
/assets/
/media/
فقط فایل عمومی داشته باشند.
و:
/account/
/dashboard/
/api/private/
هرگز وارد Cache Rule عمومی نشوند.
این Design باعث میشود Cache برای تصمیمگیری مجبور نباشد URL پیچیده Application را حدس بزند.
Catch-All Routeها را محدود کنید
Frameworkها گاهی Routeهای بسیار عمومی دارند.
مثلاً Route میتواند Segmentهای اضافی را Ignore کند.
این Behavior برای UX یا Backward Compatibility مفید است، اما از دید Cache خطر دارد.
Routeهای حساس بهتر است Path Strict داشته باشند.
یعنی:
/account
معتبر باشد.
اما:
/account/random-extra-path
به 404 برسد.
این رفتار ambiguity را کاهش میدهد.
404 واقعی اهمیت دارد
اگر Path ناشناخته به جای 404 همان صفحه اصلی یا Account Page را برگرداند، Cache ممکن است URLهای عجیب را هم Cache کند.
برای Static Namespace، File Not Found واقعاً باید 404 باشد.
برای Dynamic Endpoint نیز Path اضافی نامعتبر بهتر است Reject شود.
این اصل ساده Path Mapping را شفافتر میکند.
Content-Type را دقیق ارسال کنید
اگر Origin HTML تولید میکند:
Content-Type: text/html
ارسال شود.
اگر تصویر است:
Content-Type: image/jpeg
این Metadata به CDN Protectionهایی مثل Cache Deception Armor کمک میکند.
Cloudflare Cache Deception Armor بر تطبیق Extension و Content-Type تکیه میکند.
بنابراین MIME Type اشتباه فقط مشکل Browser نیست؛ میتواند روی Cache Security نیز اثر بگذارد.
Cache Rule نباید Cache-Control را Override کند
یکی از خطرناکترین Configurationها این است که:
Origin بگوید:
Cache-Control: no-store, private
اما CDN بگوید:
Cache Everything
اگر CDN Rule Origin Header را بیاثر کند، Developer ممکن است تصور کند Response امن است درحالیکه Edge رفتار دیگری دارد.
PortSwigger صراحتاً توصیه میکند CDN Ruleها نباید Cache-Control مربوط به Dynamic Resourceها را Override کنند.
Edge TTL با دقت تنظیم شود
Edge Cache TTL ممکن است Cache Lifetime را مستقل از Origin تعیین کند.
این قابلیت برای Static Asset مناسب است.
اما روی Route عمومی مانند:
/*
خطرناک است.
TTL اجباری نباید باعث Cache شدن محتوای Authentication-dependent شود.
Scope Cache Rule باید کوچک و قابل Audit باشد.
Cache Everything چرا حساس است؟
Cloudflare توضیح میدهد Cache Everything میتواند انواع Content بیشتری را نسبت به رفتار Default بهعنوان Static Cache کند.
این Feature ذاتاً آسیبپذیر نیست.
اما اگر روی تمام Domain اعمال شود و Origin مسیرهای Private داشته باشد، Risk بالا میرود.
Cache Everything باید با:
Bypass Rule،
Cache-Control،
Cookie Policy،
Path Exception
هماهنگ شود.
Rule Priority مهم است
CDN ممکن است چند Cache Rule داشته باشد.
Cloudflare مستند کرده است چند Rule میتوانند همزمان Match شوند و در Settingهای متعارض، آخرین Rule مرتبط تعیینکننده باشد.
این یعنی ممکن است تیم Security Rule زیر را داشته باشد:
/account → bypass
اما Rule جدید دیگری بعداً:
/* → cache
قرار گیرد و Behavior را تغییر دهد.
Cache Rule Order باید بخشی از Security Review باشد.
چگونه Web Cache Deception را امن تست کنیم؟
این موضوع حساس است، زیرا تست نادرست میتواند اطلاعات واقعی کاربر را وارد Cache کند.
تست باید روی:
Staging،
Test Account،
Cache Namespace مجزا،
و داده غیرحساس
انجام شود.
نباید برای اثبات Finding از حساب User واقعی استفاده شود.
هدف تست دفاعی این است که ببینیم:
آیا یک Dynamic Response امکان Cache شدن تحت URL ظاهراً Static را دارد یا خیر؟
نه اینکه اطلاعات واقعی استخراج کنیم.
مرحله اول تست: Cache را بشناسید
ابتدا مشخص کنید چه Cache Layerهایی وجود دارند:
CDN،
Reverse Proxy،
Application Cache،
Plugin Cache.
اگر چند Layer دارید باید بدانید Response از کدام Cache میآید.
Headerهایی مانند:
Age
X-Cache
CF-Cache-Status
ممکن است بسته به Provider کمک کنند.
نام Headerها Provider-Specific است.
مرحله دوم: Dynamic Endpoint آزمایشی
از یک Test Account استفاده کنید.
صفحهای انتخاب کنید که داده Dummy دارد.
مثلاً:
Test User
Email: [email protected]
سپس بررسی کنید Response عادی Cache میشود یا خیر.
انتظار برای صفحه شخصی:
Cache MISS / BYPASS
است.
مرحله سوم: Path Mapping را بررسی کنید
در محیط کنترلشده بررسی کنید آیا Origin Segment اضافه را نادیده میگیرد.
اگر Path غیرمعمول همچنان همان Sensitive Response را برگرداند، Routing باید بررسی شود.
PortSwigger این رفتار را Indicator مهم Path Mapping Discrepancy میداند.
هدف فقط Observation است.
از Payloadهای مخرب استفاده نمیشود.
مرحله چهارم: Cache Eligibility
بررسی کنید CDN همان URL آزمایشی را Cache میکند یا خیر.
اگر Response دارای:
no-store, private
است ولی Cache HIT میشود، Configuration مشکل دارد.
اگر URL با ظاهر Static باعث تغییر Eligibility میشود، Cache Rule باید بازبینی شود.
مرحله پنجم: بدون Session بررسی شود
در محیط Staging و با Data Dummy میتوان همان Test URL را از Session دیگر Request کرد.
اگر Response Account آزمایشی از Shared Cache ظاهر شود، Data Isolation شکسته شده است.
این روش برای تأیید Vulnerability کافی است و نیازی به اطلاعات واقعی کاربران ندارد.
تست روی Production مناسب است؟
برای این کلاس Vulnerability بهشدت بهتر است از Production اجتناب شود.
چرا؟
چون Test ممکن است Response خصوصی Tester را در Cache Shared قرار دهد.
یا Rule Cache تحت Edge Location خاصی فعال شود.
اگر ناچار به Production Verification هستید، فقط با مجوز رسمی، Account آزمایشی و داده غیرحساس و Cache Key کاملاً کنترلشده انجام شود.
SAST چه کمکی میکند؟
Web Cache Deception معمولاً از تعامل Infrastructure و Application ایجاد میشود، بنابراین SAST بهتنهایی کافی نیست.
اما میتواند مواردی مثل:
Catch-All Route،
Dynamic Routeهای با Segment اضافی،
Cache-Control ناقص،
Header Generation
را پیدا کند.
بخش Cache/CDN باید جداگانه Review شود.
DAST چه کمکی میکند؟
DAST میتواند Behavior واقعی URL و Cache را مشاهده کند.
اما Scanner باید Cache-Aware باشد.
PortSwigger ابزارها و Scannerهایی برای شناسایی Path Mapping Discrepancy در محیطهای مجاز ارائه کرده است.
برای Production اسکن Aggressive توصیه نمیشود.
تست Configuration مهمتر از Payload است
در Web Cache Deception سؤال اصلی این نیست:
«چه Payload خطرناکی میتوان وارد کرد؟»
بلکه:
«آیا Cache و Origin URL را متفاوت تفسیر میکنند؟»
بنابراین Security Testing بیشتر روی:
Routing،
Normalization،
Cache-Control،
Cache Rule،
Content-Type،
Authentication Dependency
تمرکز دارد.
Monitoring برای Web Cache Deception
میتوان رفتارهای مشکوک را Monitor کرد.
مثلاً درخواستهای Account Route با Extensionهای غیرعادی.
یا افزایش Cache HIT روی Routeهایی که باید Dynamic باشند.
Signalهای مفید:
Cache HIT روی /account،
Cache HIT روی API خصوصی،
Extension غیرمنتظره در Route شخصی،
Cache Entry دارای Set-Cookie،
Response text/html برای Path ظاهراً Image،
Cache Rule Changes.
Monitoring جای Fix را نمیگیرد، اما Detection را سریعتر میکند.
آیا Set-Cookie مانع Cache شدن است؟
نباید چنین فرضی کرد.
RFC 9111 صراحتاً هشدار میدهد وجود Set-Cookie بهخودیخود مانع Cache شدن Response نیست و Serverهایی که میخواهند Cache را کنترل کنند باید Cache-Control مناسب ارسال کنند.
این نکته بسیار مهم است.
قاعده غلط:
Response has cookie → therefore not cached
قاعده صحیح:
Explicit caching policy controls behavior.
Cache باید اطلاعات حساس تلقی شود
RFC 9111 در Security Considerations تأکید میکند Cache Content میتواند مدتها پس از پایان Request باقی بماند و باید بهعنوان اطلاعات حساس محافظت شود. همچنین Implementation/Deployment Flaw ممکن است باعث Cache شدن اطلاعاتی شود که Private تصور میشدهاند.
این دقیقاً فلسفه دفاع در برابر Web Cache Deception است.
Cache یک Database موقت عمومی نیست.
Purge بعد از کشف آسیبپذیری
اگر مشخص شود محتوای خصوصی Cache شده، Patch Application کافی نیست.
Entryهای قبلی ممکن است تا پایان TTL باقی بمانند.
Incident Response باید شامل:
Purge Cache،
غیرفعالسازی موقت Cache Rule،
اصلاح Origin Header،
و بررسی Log
باشد.
اگر معلوم نیست چه URLهایی Poison نشده بلکه Deceived شدهاند، ممکن است Purge گستردهتری لازم باشد.
بررسی Logها
برای Investigation میتوان موارد زیر را بررسی کرد:
URLهای غیرعادی،
Extensionهای غیرمنتظره،
Cache HIT/MISS،
Session Presence،
Origin Response Type،
Cache Age،
Edge Location،
User Agent،
و Timestamp.
اما Log نباید Session Cookie یا Credential کامل را ذخیره کند.
Investigation نباید Information Disclosure جدید ایجاد کند.
Web Cache Deception و Incident Response
اگر احتمال نشت اطلاعات وجود دارد، باید Scope مشخص شود.
چه Endpointهایی Cacheable بودهاند؟
چه نوع Dataای در Response وجود داشته؟
TTL چقدر بوده؟
آیا Cache Entry از چند Region قابل دریافت بوده؟
چه Userهایی URL مربوط را Request کردهاند؟
چه Clientهایی بعداً Cache HIT داشتهاند؟
آیا Data شامل Token امنیتی بوده؟
این اطلاعات برای تعیین Impact واقعی ضروریاند.
Severity چگونه تعیین میشود؟
Web Cache Deception Severity ثابت ندارد.
اگر فقط Theme Preference افشا شود، Impact پایینتر است.
اگر اطلاعات Account، سفارش یا Token افشا شود، Impact بالاتر است.
عوامل مهم:
نوع Data،
نیاز به Interaction قربانی،
TTL،
Cache Scope،
تعداد قربانیان،
امکان تکرار،
Authentication Level،
و قابلیت Automation.
PortSwigger Knowledge Base این Finding را معمولاً با Severity متوسط دستهبندی میکند، اما Severity واقعی باید بر اساس داده قابل افشا تعیین شود.
اشتباهات رایج توسعهدهندگان
«این صفحه Login میخواهد، پس Cache مشکلی ندارد»
Authentication فقط Origin Request را محافظت میکند.
Cache HIT ممکن است Origin را دور بزند.
«URL با .css تمام میشود، پس حتماً Static است»
Extension ظاهر URL است.
Resource واقعی را Origin Routing تعیین میکند.
«CDN معروف است، پس خودکار امن است»
CDN نمیتواند Business Semantics Routeهای شما را حدس بزند.
Configuration مسئولیت شماست.
«Set-Cookie داریم، پس Response Cache نمیشود»
RFC 9111 چنین تضمینی نمیدهد.
«no-cache یعنی ذخیره نشود»
no-cache با no-store یکسان نیست.
برای جلوگیری از Storage محتوای حساس، no-store نقش مهمتری دارد.
«Cache Everything سرعت سایت را بالا میبرد»
ممکن است، اما بدون Bypass Rule دقیق میتواند اطلاعات خصوصی را Cache کند.
«فقط WordPress Plugin را تنظیم میکنیم»
CDN و Reverse Proxy ممکن است قبل از WordPress Response بدهند.
Policy باید End-to-End باشد.
طراحی امن Cache
یک معماری ساده و امنتر:
Public static assets
↓
Shared CDN Cache
Public HTML
↓
Controlled cache policy
Authenticated / personalized pages
↓
No shared cache
Private API
↓
No shared cache
این تفکیک از Cache Ruleهای بسیار پیچیده قابلاعتمادتر است.
Cache Allowlist بهتر از Cache Denylist است
بهجای اینکه بگویید:
همهچیز را Cache کن
بهجز این 30 مسیر
برای Application حساس بهتر است بگویید:
فقط این Static Namespaceها را Cache کن.
مثلاً:
/wp-content/uploads/
/wp-content/themes/
/assets/
/static/
این مدل خطر فراموش کردن Route خصوصی جدید را کاهش میدهد.
Secure by Design در Cache
Security نباید فقط مجموعه Headerهایی باشد که بعداً اضافه میشوند.
Cache باید از ابتدا بخشی از Architecture باشد.
هنگام ساخت هر Endpoint مشخص کنید:
Public است یا Private؟
Dynamic است یا Static؟
به Session وابسته است؟
Cacheable است؟
کجا Cache میشود؟
TTL چقدر است؟
Cache Key چیست؟
چه کسی Purge میکند؟
این سؤالها باید همان زمان طراحی Feature پاسخ داده شوند.
چکلیست دفاعی جلوگیری از Web Cache Deception
| کنترل | وضعیت امن |
|---|---|
| صفحات خصوصی | Shared Cache غیرفعال |
| Cache-Control | no-store, private برای محتوای حساس |
| CDN | احترام به Origin Cache-Control |
| Cache Everything | فقط در Scope دقیق و بررسیشده |
| Static extensions | معیار تنها برای Cache نباشند |
| Static directories | فقط محتوای واقعاً Static |
| Path Routing | Path اضافی نامعتبر Reject شود |
| Catch-All Routes | روی Endpointهای حساس محدود شوند |
| URL Normalization | Cache و Origin رفتار هماهنگ داشته باشند |
| Delimiters | تفاوت Parserها بررسی شود |
| Encoded paths | Decode/Normalize Order بررسی شود |
| Content-Type | دقیق و مطابق Resource واقعی |
| Cache Deception Protection | در CDN فعال شود، اگر موجود است |
| Logged-in WordPress | Cache Headerهای Core حفظ شوند |
| REST API | Endpoint شخصی Cache عمومی نشود |
| WooCommerce | Cart، Checkout و Account Bypass شوند |
| Membership | Dashboard و Member Area Cache نشوند |
| Private Downloads | Cache Policy و Authorization صریح |
| Monitoring | HIT روی مسیرهای خصوصی Alert شود |
| Purge | امکان پاکسازی سریع Cache وجود داشته باشد |
| Testing | فقط با Account و Data آزمایشی |
چکلیست ویژه WordPress
در WordPress ابتدا مشخص کنید چند Layer Cache دارید.
Plugin Cache، CDN و Hosting Cache ممکن است Ruleهای متفاوت داشته باشند.
nocache_headers() و Headerهای Core باید حفظ شوند. WordPress در wp_get_nocache_headers() اکنون no-store و private را نیز در Cache-Control قرار میدهد.
همچنین بررسی کنید:
صفحات Login شده Cache نشوند.
Custom Account Routeها Exclude شوند.
REST Endpointهای شخصی Exclude شوند.
WooCommerce Session Pageها Exclude شوند.
Path عجیب به Dashboard واقعی Resolve نشود.
CDN Origin Header را Override نکند.
Cache Rule فقط Static Namespaceهای واقعی را پوشش دهد.
گزارش حرفهای Web Cache Deception
گزارش خوب باید نشان دهد اختلاف دقیق کجاست.
مثلاً:
Affected endpoint:
Authenticated account page
Origin interpretation:
The modified path still maps to the account controller.
Cache interpretation:
The request is considered a static resource and becomes cacheable.
Result:
The authenticated response is stored in the shared cache.
Impact:
Another unauthenticated client can receive the cached test account data.
Remediation نیز باید مشخص باشد:
Set no-store/private on personalized responses.
Do not override these directives at the CDN.
Reject unexpected path suffixes.
Restrict caching to explicit static namespaces.
Purge affected cache entries.
این نوع Report مستقیم قابل اقدام است.
آیا WAF جلوی Web Cache Deception را میگیرد؟
WAF ممکن است بعضی Pathهای غیرمعمول را Block کند.
اما Root Cause را حل نمیکند.
یک URL ممکن است کاملاً از نظر Syntax معتبر باشد و همچنان Cache و Origin آن را متفاوت تفسیر کنند.
راهکار اصلی:
Routing هماهنگ،
Cache Policy،
و Shared Cache Isolation
است.
WAF فقط لایه مکمل محسوب میشود.
آیا HTTPS از Web Cache Deception جلوگیری میکند؟
خیر.
HTTPS ارتباط Client با CDN یا Server را رمزنگاری میکند.
اما اگر CDN قانونی خود سایت Response خصوصی را ذخیره و به مهاجم تحویل دهد، HTTPS همان Response را بهصورت امن و رمزنگاریشده به مهاجم میرساند.
TLS جلوی Logic Error در Cache را نمیگیرد.
آیا CSP کمک میکند؟
CSP برای کنترل Script و Resource Loading طراحی شده است.
Web Cache Deception عمدتاً Confidentiality Problem است.
CSP نمیتواند مانع Cache شدن Profile Response شود.
بنابراین نقش اصلی در این آسیبپذیری ندارد.
آیا SameSite Cookie جلوی حمله را میگیرد؟
SameSite میتواند بعضی Cross-Site Requestها و CSRF Scenarioها را محدود کند، اما Web Cache Deception را بهطور عمومی حل نمیکند.
Attack Scenario و نحوه هدایت قربانی اهمیت دارد.
حتی اگر Cookie فقط در Navigation مناسب ارسال شود، Root Problem یعنی Cache شدن Response خصوصی همچنان باید اصلاح شود.
Cache Security نباید به Cookie Policy وابسته باشد.
Defense in Depth پیشنهادی
یک مدل مناسب:
Internet
↓
CDN
Only explicit public resources cacheable
↓
Reverse Proxy
Strict path normalization
↓
Application
Strict routing
↓
Authenticated resources
Cache-Control: no-store, private
و در کنار آن:
Correct Content-Type
Cache deception protection
Monitoring
Fast purge
Regression testing
میتواند Risk را بهشدت کاهش دهد.
تست Regression بعد از اصلاح
بعد از Fix فقط URL اولیه را تست نکنید.
باید بررسی شود:
Path استاندارد Private Cache نمیشود.
Path دارای Segment اضافی Reject میشود.
Representationهای Encodeشده همان Policy را دارند.
CDN Cache-Control را رعایت میکند.
Static Assetها همچنان Cache میشوند.
Authenticated API Cache نمیشود.
Anonymous Request نمیتواند Response Test User را ببیند.
این Testها بهتر است وارد CI/CD یا Security Regression Suite شوند.
تغییر CDN نیازمند تست امنیت مجدد است
مهاجرت از یک CDN به CDN دیگر فقط تغییر Performance نیست.
Cache Providerها ممکن است در موارد زیر فرق داشته باشند:
Default Extensions،
Query Handling،
URL Normalization،
Delimiter Processing،
Origin Header Respect،
Cache Key.
بنابراین هر Migration CDN باید Security Review Cache داشته باشد.
حتی Upgrade Proxy نیز میتواند Parsing Behavior را تغییر دهد.
سؤال کلیدی در Audit
برای هر Endpoint حساس این سؤال را مطرح کنید:
آیا هیچ Representation دیگری از این URL وجود دارد
که Origin آن را همان Resource خصوصی بداند
اما Cache آن را Static و عمومی تصور کند؟
اگر جواب احتمالی «بله» است، Web Cache Deception باید جدی بررسی شود.
سؤالات متداول درباره Web Cache Deception
Web Cache Deception چیست؟
Web Cache Deception آسیبپذیریای است که Cache را فریب میدهد تا محتوای خصوصی و Dynamic کاربر را بهعنوان Resource عمومی ذخیره کند. مهاجم سپس میتواند همان Cached Response را بدون دسترسی مستقیم به Session قربانی دریافت کند.
Web Cache Deception چگونه کار میکند؟
معمولاً Cache و Origin URL را متفاوت تفسیر میکنند. Origin URL غیرعادی را همچنان به Endpoint خصوصی نگاشت میکند، اما Cache آن را به دلیل Extension، Directory یا File Name خاص Static تلقی کرده و Response را ذخیره میکند.
چه اطلاعاتی ممکن است افشا شود؟
هر دادهای که در Response Dynamic قربانی وجود داشته باشد؛ برای مثال Profile، Email، اطلاعات سفارش، تنظیمات Account، بعضی Tokenهای داخل صفحه یا داده API.
تفاوت Web Cache Deception و Web Cache Poisoning چیست؟
در Cache Deception قربانی باعث Cache شدن Response خصوصی خودش میشود و مهاجم آن را میخواند. در Cache Poisoning مهاجم Response دستکاریشده را در Cache قرار میدهد تا دیگران دریافت کنند.
چرا فایلهای CSS یا JPG در این حمله مطرح میشوند؟
Cacheها اغلب Pathهای دارای Extension استاتیک مانند .css، .js و .jpg را قابل Cache میدانند. اگر Origin همان Path را به Dynamic Endpoint نگاشت کند، Cache ممکن است Response خصوصی را Static تصور کند.
Path Mapping Discrepancy چیست؟
زمانی است که Cache و Origin یک URL Path را به Resourceهای متفاوت یا با Semantics متفاوت نگاشت میکنند. این اختلاف از Root Causeهای اصلی Web Cache Deception است.
Delimiter Discrepancy چیست؟
وقتی Cache و Origin درباره معنای Characterهای جداکننده URL توافق ندارند. یک Component ممکن است بخشی از Path را نادیده بگیرد و دیگری آن را بخشی از نام Resource بداند.
URL Normalization چه ارتباطی با Cache Deception دارد؟
اگر Cache و Origin Encoding، Dot Segment یا سایر Representationهای Path را با ترتیب متفاوت Normalize کنند، ممکن است Cache Resource را Static و Origin آن را Dynamic تفسیر کند.
بهترین روش جلوگیری از Web Cache Deception چیست؟
محتوای شخصی را با Cache-Control: no-store, private از Shared Cache خارج کنید، Cache Ruleها را به Static Resourceهای واقعی محدود کنید و مطمئن شوید Origin و Cache URL را به شکل هماهنگ Parse میکنند.
Cache-Control: no-store چه میکند؟
به Cache میگوید Response را ذخیره نکند. برای Responseهای بسیار حساس یکی از مهمترین Directiveهاست.
Cache-Control: private چیست؟
مشخص میکند Response نباید در Shared Cache ذخیره شود و برای استفاده عمومی مناسب نیست.
آیا Set-Cookie جلوی Cache شدن Response را میگیرد؟
خیر، نباید به آن تکیه کرد. RFC 9111 تصریح میکند وجود Set-Cookie لزوماً مانع Cache شدن نیست و Server باید Cache-Control مناسب ارسال کند.
آیا CDNها خودشان از Cache Deception جلوگیری میکنند؟
بعضی Providerها Protection دارند، اما Configuration همچنان مسئولیت سایت است. Cloudflare برای نمونه Cache Deception Armor را ارائه میکند که Extension URL را با Content-Type Response مقایسه میکند.
Cache Deception Armor چیست؟
قابلیتی در Cloudflare است که در بعضی Cache Ruleها بررسی میکند نوع فایل ظاهر URL با Content-Type Response سازگار باشد؛ در صورت mismatch مشکوک، Response Cache نمیشود.
آیا Cache Deception Armor بهتنهایی کافی است؟
خیر. Cache-Control، Origin Routing و Cache Ruleهای دیگر همچنان باید صحیح باشند.
Web Cache Deception در WordPress ممکن است رخ دهد؟
بله، اگر WordPress پشت CDN یا Page Cache نامناسب قرار گرفته باشد یا Custom Route خصوصی به شکلی Cacheable شود. WordPress برای Contextهای حساس توابعی مانند nocache_headers() دارد.
WordPress برای کاربران Loginشده چه Headerهایی استفاده میکند؟
نسخههای فعلی wp_get_nocache_headers() Cache-Control شامل no-cache, must-revalidate, max-age=0, no-store و private تولید میکنند.
آیا WooCommerce باید Full Page Cache شود؟
Cart، Checkout، My Account و سایر صفحات Session-Specific نباید Shared Full-Page Cache عادی داشته باشند.
آیا GET Request همیشه قابل Cache است؟
خیر. GET میتواند Response شخصی و Sensitive داشته باشد. Cacheability باید براساس Semantics Resource و Cache-Control تعیین شود.
آیا Web Cache Deception نیاز به XSS دارد؟
خیر. Web Cache Deception مستقل از XSS است و هدف اصلی آن افشای Response خصوصی است.
آیا Authentication جلوی آن را میگیرد؟
نه لزوماً. Authentication در Origin میتواند صحیح باشد، ولی Cached Response بعداً بدون مراجعه به Origin تحویل داده شود.
آیا HTTPS جلوی آن را میگیرد؟
خیر. HTTPS فقط Transport را امن میکند و Cache Policy اشتباه را اصلاح نمیکند.
بعد از کشف Vulnerability چه باید کرد؟
Cache Rule آسیبپذیر را Bypass یا اصلاح کنید، Entryهای مربوط را Purge کنید، Cache-Control صفحات خصوصی را اصلاح کنید، Routing و Normalization را هماهنگ کنید و Logها را برای Exposure احتمالی بررسی کنید.
جمعبندی
Web Cache Deception یکی از مهمترین نمونههای آسیبپذیریهایی است که نه صرفاً در Code و نه صرفاً در Infrastructure ایجاد میشوند، بلکه از تعامل اشتباه میان چند Component به وجود میآیند.
Origin Server ممکن است رفتار کاملاً منطقی داشته باشد.
CDN نیز ممکن است Cache Rule کاملاً رایجی داشته باشد.
اما ترکیب آنها ناامن شود.
Origin یک URL را Dynamic و مربوط به Profile User میداند.
Cache همان URL را به دلیل Extension، Directory یا File Name ظاهراً Static میبیند.
قربانی با Session معتبر URL را Request میکند.
Origin اطلاعات خصوصی او را تولید میکند.
Cache Response را ذخیره میکند.
و مهاجم همان URL را دوباره Request کرده و اطلاعات Cacheشده را دریافت میکند.
PortSwigger این اختلاف در نحوه پردازش Request میان Origin و Cache را Root Mechanism اصلی Web Cache Deception معرفی میکند.
یکی از رایجترین نقاط ضعف، Static Extension Rule است.
Cache ممکن است .css، .js یا .jpg را Public فرض کند، در حالی که Framework بخش آخر Path را نادیده میگیرد و همچنان Dynamic Resource اصلی را Render میکند. اختلاف در Path Mapping، Delimiterها، URL Decoding و Normalization نیز میتواند همین نتیجه را ایجاد کند.
مهمترین دفاع این است که Cache Eligibility صریح باشد.
صفحهای که User-Specific است نباید صرفاً بهدلیل ظاهر URL وارد Shared Cache شود.
Responseهای حساس باید Cache-Control: no-store, private داشته باشند و CDN باید این Policy را رعایت کند.
همچنین Static Assetها بهتر است در Namespaceهای مشخص مانند /assets/ و /static/ قرار بگیرند و Dynamic Routeهای حساس Path Strict داشته باشند.
Cloudflare و برخی CDNهای دیگر ابزارهای تکمیلی برای مقابله با Cache Deception دارند. برای نمونه Cache Deception Armor در Cloudflare میتواند Extension URL را با Content-Type Response مقایسه کند و از Cache شدن بعضی mismatchهای مشکوک جلوگیری کند. اما این قابلیت جای Secure Routing و Cache-Control صحیح را نمیگیرد.
در WordPress نیز Core برای بسیاری از Responseهای حساس No-Cache Header ارسال میکند. wp_get_nocache_headers() در نسخههای فعلی Directiveهای no-store و private را نیز شامل میشود، اما CDN، Hosting Cache یا Plugin خارجی میتواند Policy متفاوتی ایجاد کند؛ به همین دلیل Cache Security باید End-to-End بررسی شود.
Web Cache Deception در اصل یک سؤال ساده را مطرح میکند:
«آیا ممکن است Origin این URL را مربوط به اطلاعات خصوصی کاربر بداند، در حالی که Cache همان URL را Resource عمومی و قابل ذخیره تلقی کند؟»
اگر پاسخ مثبت باشد، Risk جدی نشت اطلاعات وجود دارد.
طراحی درست Cache باید تضمین کند هیچ Dynamic Response شخصی فقط به دلیل شکل ظاهری URL، Extension فایل یا Interpretation متفاوت Path به Shared Cache راه پیدا نکند.