Przejdź do treści
INDEKS ANALIZ BREACHROAD / NOTA TECHNICZNA

Web Cache Poisoning i Deception: pentest CDN

Jak bezpiecznie testować web cache poisoning i cache deception: cache key, normalizacja URL, CDN, Vary, prywatne odpowiedzi, detekcja i hardening.

MATERIAŁ PUBLICZNY
AUTOR
/ CEO Breachroad · OSCP · PNPT
PUBLIKACJA
5 kwietnia 2026
CZAS CZYTANIA
21 min czytania
TEMAT
Pentest i AppSec
Web Cache Poisoning i Deception: pentest CDN

Web Cache Poisoning i Web Cache Deception wykorzystują różnicę między tym, jak cache oraz origin rozumieją żądanie, ale prowadzą do innego skutku. W poisoning atakujący wpływa na odpowiedź zapisaną pod współdzielonym kluczem, więc zmodyfikowana treść trafia do kolejnych użytkowników. W deception ofiara otwiera spreparowaną ścieżkę, origin generuje prywatną odpowiedź, a pośrednik błędnie uznaje ją za zasób publiczny i zapisuje do cache.

Najkrótsza odpowiedź: bezpieczny pentest cache zaczyna się od odtworzenia cache key oraz polityki cacheability na każdej warstwie. Następnie wykorzystuje losowe parametry, syntetyczne dane i dedykowaną trasę, aby sprawdzić komponenty nieuwzględnione w kluczu, normalizację ścieżki oraz ochronę odpowiedzi uwierzytelnionych. Tester nie zatruwa popularnej strony i nie próbuje pobierać cache wpisu realnego użytkownika. Każdy dowód powinien dać się natychmiast usunąć przez purge.

Temat wykracza poza CDN. Cache może działać w przeglądarce, reverse proxy, gatewayu, frameworku, warstwie fragmentów HTML, service workerze i aplikacji mobilnej. Dwie warstwy mogą używać innych kluczy oraz inaczej dekodować URL, co tworzy podatność mimo poprawnej konfiguracji każdej z nich ocenianej osobno.

Cache key i cache policy: dwa różne mechanizmy

Cache podejmuje dwie podstawowe decyzje:

  1. czy odpowiedź wolno przechować — na podstawie metody, statusu, nagłówków, konfiguracji i reguł produktu;
  2. pod jakim kluczem ją zapisać — zwykle na podstawie schematu, hosta, metody, ścieżki, query string oraz wybranych nagłówków lub cookies.

RFC 9111 definiuje semantykę cache HTTP, między innymi dyrektywy private, no-store, s-maxage i mechanizm Vary. CDN może jednak stosować własne reguły i nadpisywać decyzje originu. Dokumentacja Cloudflare Cache Keys pokazuje, że konfiguracja może włączać lub wyłączać query parameters, nagłówki, cookies, host i cechy użytkownika.

Bezpieczeństwo wymaga zgodności trzech funkcji:

FunkcjaPytanieRyzyko rozbieżności
parser requestujaki jest host, path i parametr?CDN i origin normalizują URL inaczej
generator cache keyktóre elementy odróżniają odpowiedzi?istotny nagłówek lub cookie nie trafia do klucza
polityka cacheabilityczy tę odpowiedź można współdzielić?treść prywatna zostaje uznana za statyczną

Komponent nieuwzględniony w kluczu nazywa się unkeyed input. Sam w sobie nie jest podatnością. Problem pojawia się, gdy zmienia odpowiedź, która następnie zostaje udostępniona innym użytkownikom pod tym samym kluczem.

Web Cache Poisoning a Web Cache Deception

Na czym polega cache poisoning

W typowym scenariuszu proxy nie uwzględnia konkretnego nagłówka lub parametru w cache key, ale aplikacja używa go do budowy linku, redirectu, nagłówka bezpieczeństwa albo fragmentu HTML. Atakujący tworzy wariant odpowiedzi zawierający kontrolowany canary. Jeżeli cache zapisze go pod kluczem używanym przez zwykłe żądania, nastąpiła kolizja bezpieczeństwa.

Wpływ zależy od miejsca odbicia danych. Może ograniczyć się do błędnego linku, ale bywa źródłem stored XSS, przekierowania, podmiany importu JavaScript, ujawnienia nagłówka albo dostępności. Podstawowe badania Practical Web Cache Poisoning i Web Cache Entanglement pokazują, że ryzyko powstaje często między warstwami oraz mechanizmami normalizacji.

Na czym polega cache deception

W deception origin i cache nie zgadzają się, czy ścieżka jest dynamiczna. Aplikacja może ignorować dodatkowy segment po właściwej trasie i nadal zwrócić panel konta, podczas gdy CDN rozpoznaje pozorne rozszerzenie zasobu statycznego i zapisuje odpowiedź. Innym źródłem jest różnica w dekodowaniu separatora, średnika, segmentu dot albo kodowania procentowego.

Atak zwykle wymaga nakłonienia zalogowanej ofiary do wejścia pod unikalny URL, a następnie pobrania zapisanej kopii. To nie jest klasyczne poisoning: atakujący nie tworzy szkodliwej odpowiedzi, lecz powoduje utrwalenie odpowiedzi ofiary. OWASP WSTG: Test for Path Confusion opisuje tę klasę rozbieżności routingu i cache.

Dlaczego cache jest trudny do testowania

Jeden adres może przechodzić przez cache przeglądarki, POP CDN, regionalny shield, reverse proxy i cache aplikacyjny. Każdy ma inny TTL, zasięg, mechanizm purge i nagłówki diagnostyczne. Odpowiedź HIT nie dowodzi, który poziom zadziałał. Brak Age nie dowodzi braku cache — produkt może usuwać informacje diagnostyczne.

Dodatkowe źródła niepewności to:

  • warianty kompresji i Accept-Encoding;
  • geografia POP oraz różne originy regionalne;
  • personalizacja przez cookies lub nagłówki językowe;
  • stale-while-revalidate i asynchroniczne odświeżanie;
  • fragment caching wewnątrz aplikacji;
  • cache błędów WAF i redirectów;
  • normalizacja query string w innej kolejności;
  • różnice między HEAD i GET;
  • klucz po transformacji adresu inny niż URL wysłany do originu.

Dlatego każdy test musi używać korelacyjnego znacznika, powtarzalnej sekwencji i kilku niezależnych obserwacji. Losowy cache buster jest narzędziem bezpieczeństwa: izoluje wpis testera od publicznego ruchu.

Zakres i zasady bezpiecznego pentestu cache

Przed rozpoczęciem ustal warstwy, domeny, środowiska, konta i procedurę purge. Zespół CDN powinien potwierdzić, czy testowe adresy można przypiąć do osobnej cache namespace albo reguły. Rules of engagement powinny zakazywać:

  • zatruwania strony głównej, loginu i popularnych zasobów;
  • wykorzystywania danych prawdziwego użytkownika;
  • testów trwałego denial of service bez osobnej zgody;
  • masowego rozgrzewania POP;
  • zgadywania unikalnych URL zapisanych przez inne osoby;
  • pozostawienia testowych wpisów po zakończeniu.

Najlepszym dowodem jest syntetyczna odpowiedź w testowym tenancie. Dla poisoning umieść nieszkodliwy token w kontrolowanym polu i pokaż, że pojawia się po żądaniu bez tego wejścia, ale z tym samym izolowanym kluczem. Dla deception zaloguj się jako konto testera, zapisz fałszywy „sekret” bez wartości produkcyjnej, odwiedź unikalną ścieżkę i sprawdź ją w drugiej, własnej sesji.

Całość powinna być elementem szerszych testów penetracyjnych aplikacji webowych, ponieważ cache często wzmacnia istniejący błąd XSS, redirect, autoryzacji albo ujawnienia danych.

Techniczna metodyka testu cache poisoning

1. Zmapuj wszystkie warstwy i reguły

Zbierz konfigurację CDN, Cache Rules, origin headers, reverse proxy, framework i service worker. Dla każdej trasy zapisz TTL, statusy cacheable, metody, query policy, cookies, Vary, zasady bypass, stale content i purge. Oddziel treść publiczną, prywatną, zależną od roli, języka, urządzenia oraz tenanta.

Utwórz tabelę oczekiwanych wariantów. Jeżeli odpowiedź zmienia się według języka, ale język nie jest w kluczu ani nie ma poprawnego Vary, to jest błąd projektu nawet bez exploita.

2. Odtwórz rzeczywisty cache key

Wysyłaj pary żądań różniące się jednym elementem: parametrem, kolejnością parametrów, nagłówkiem, cookie, hostem, portem albo kodowaniem ścieżki. Każda para musi używać własnego losowego namespace. Porównuj body hash, status, Age, ETag, nagłówki produktu i log originu.

Jeżeli drugie żądanie nie dociera do originu i otrzymuje wariant pierwszego, element prawdopodobnie nie należy do klucza. Weryfikuj wynik w kilku cyklach MISS→HIT, ponieważ wewnętrzne retry lub load balancing mogą imitować cache.

3. Znajdź unkeyed inputs zmieniające odpowiedź

Analizuj nagłówki forwardujące, informacje o schemacie, host, ścieżkę, nagłówki negocjacji, cookies i parametry ignorowane przez klucz. Używaj wyłącznie neutralnego tekstu canary. Sprawdź, czy wpływa na redirect, canonical URL, linki, skrypty, metadata i nagłówki odpowiedzi.

Nie zaczynaj od aktywnych payloadów XSS. Najpierw udowodnij zależność: wejście A zmienia pole B, a B zostaje zwrócone przy zwykłym żądaniu C. To wystarcza do potwierdzenia mechanizmu i pozwala bezpiecznie oszacować potencjalny skutek.

4. Zbadaj normalizację i wielowarstwowe cache

Porównaj URL przed i po dekodowaniu, sposób obsługi separatorów, wielokrotnych slashy, końcowej kropki, wielkości liter i parametrów ścieżki. Testuj wyłącznie w dedykowanej trasie. Kluczową obserwacją jest to, czy warstwa zewnętrzna i wewnętrzna tworzą różne odpowiedniki tego samego adresu.

W przypadku dwóch cache ustal cztery stany: miss/miss, hit/miss, miss/hit i hit/hit. Błąd może pojawiać się tylko wtedy, gdy cache wewnętrzny zmieni odpowiedź, którą następnie zapisze CDN. Jeżeli po drodze występuje rozbieżność granic żądania, potrzebny jest również osobny pentest HTTP Request Smuggling i desync, ponieważ zatrucie połączenia może zmienić dane trafiające do klucza.

5. Potwierdź zasięg i usuń wpis

Sprawdź, czy wpis jest lokalny dla jednego POP, regionu czy globalny, ale nie generuj ruchu do wszystkich węzłów. W raporcie rozdziel zasięg techniczny od prawdopodobnego wpływu biznesowego. Natychmiast wykonaj purge testowego klucza i potwierdź w logach, że nie jest już serwowany.

Techniczna metodyka testu cache deception

1. Wybierz prywatną odpowiedź syntetyczną

Użyj konta bez realnych danych i umieść w profilu losowy token. Potwierdź, że normalna trasa ma Cache-Control: private, no-store lub jest omijana przez CDN. Następnie testuj wyłącznie unikalne warianty ścieżki, których nie odwiedzi żaden użytkownik.

2. Porównaj routing originu z klasyfikacją CDN

Origin powinien zwracać 404 dla nieznanych sufiksów zamiast tolerować dodatkowy path_info. CDN nie powinien określać cacheability jedynie na podstawie pozornego rozszerzenia. Obserwuj logi obu warstw: jaka ścieżka została wysłana do aplikacji i pod jakim kluczem zapisano odpowiedź.

3. Sprawdź izolację sesji

Po wygenerowaniu odpowiedzi w sesji testowej wykonaj żądanie bez cookies albo z drugiego konta testera. Jeżeli syntetyczny token jest widoczny z cache bez wywołania originu, poufność została naruszona. Zatrzymaj test, wykonaj purge i nie próbuj uzyskiwać danych innych kont.

4. Oceniaj redirecty i błędy

Niektóre stosy zapisują 301, 302, 404 albo odpowiedź WAF zbyt agresywnie. Sprawdź, czy błąd uwierzytelnionego żądania może stać się publicznym wariantem oraz czy Set-Cookie jest usuwane lub powoduje bypass cache. Cache nie powinien przechowywać treści zależnej od sesji tylko dlatego, że status wygląda statycznie.

Detekcja cache poisoning i deception

Połącz log aplikacji, edge i system konfiguracji. Wysokiej jakości sygnały to:

  • cache HIT dla odpowiedzi zawierającej Set-Cookie, dane konta lub nagłówek autoryzacji;
  • duża różnica treści dla jednego cache key;
  • origin path inny niż znormalizowany klucz CDN;
  • nagły wzrost purge albo nietypowe zmiany reguł cache;
  • publiczny HIT po wcześniejszym uwierzytelnionym MISS;
  • nieznany nagłówek wpływający na body lub redirect, mimo że nie należy do klucza;
  • prywatna trasa z TTL lub Age większym od zera;
  • nietypowe pozorne rozszerzenia plików po ścieżkach konta.

Przechowuj hash odpowiedzi i klasyfikację danych, nie pełne prywatne body. Skan ciągły może porównywać oczekiwany model wariantów z konfiguracją CDN. Zmiana cache rule powinna przechodzić review tak samo jak kod aplikacji.

Hardening: bezpieczna konfiguracja cache

  1. Cache’uj jawnie zdefiniowane zasoby publiczne, zamiast próbować wykluczać wszystkie prywatne trasy.
  2. Nigdy nie przechowuj odpowiedzi z Authorization, sesją lub danymi użytkownika bez formalnie zaprojektowanego wariantu prywatnego.
  3. Ustawiaj Cache-Control: no-store, private dla treści wrażliwej i upewnij się, że CDN tego nie nadpisuje.
  4. Buduj cache key z każdego elementu, który legalnie zmienia odpowiedź; usuń niepotrzebne unkeyed inputs.
  5. Stosuj Vary świadomie i testuj ryzyko eksplozji kluczy.
  6. Normalizuj URL identycznie na edge i originie oraz wysyłaj do backendu tę samą reprezentację, która tworzy klucz.
  7. Odrzucaj nieoczekiwane dodatkowe segmenty i path parameters na trasach dynamicznych.
  8. Nie klasyfikuj statyczności wyłącznie po rozszerzeniu; użyj jawnej listy katalogów lub manifestu zasobów.
  9. Oddziel hosty zasobów statycznych od aplikacji uwierzytelnionej.
  10. Ogranicz TTL błędów, redirectów i odpowiedzi WAF; nie zapisuj ich domyślnie.
  11. Monitoruj i wersjonuj konfigurację, a po zmianie wykonuj test MISS/HIT dla macierzy ról.
  12. Zapewnij szybki purge per URL, tag i namespace oraz przećwicz procedurę incydentową.

Kontrole można mapować do OWASP ASVS 5. Dla aplikacji API sprawdź też checklistę REST, GraphQL i OAuth; cache gatewayu może ominąć prawidłową autoryzację backendu. Jeżeli CDN łączy się z wieloma originami w chmurze, pentest AWS, Azure i GCP powinien objąć konfigurację storage, load balancerów i prywatnych endpointów.

Checklista przed wdrożeniem i retestem

  • Mamy mapę wszystkich cache od przeglądarki po aplikację.
  • Dla każdej trasy znamy cacheability, key, TTL, zasięg i purge.
  • Dane zależne od użytkownika nie trafiają do shared cache.
  • Wszystkie legalne warianty odpowiedzi należą do cache key lub Vary.
  • Edge i origin identycznie normalizują path i query.
  • Dynamiczne trasy odrzucają nieoczekiwane suffixy.
  • Test używa osobnego namespace i syntetycznych danych.
  • PoC nie dotyka popularnego klucza ani prawdziwego użytkownika.
  • Logi korelują request, origin fetch, key, HIT/MISS i purge.
  • Reguły cache są wersjonowane i zatwierdzane w code review.
  • Po poprawce testujemy poisoning, deception i legalne warianty.
  • Procedura incydentowa potrafi szybko unieważnić wpis globalnie.

Źródła techniczne

Podejrzewasz błąd w CDN lub reverse proxy? Autoryzowany test powinien odtworzyć klucz i reguły każdej warstwy, użyć syntetycznych danych oraz zakończyć się kontrolowanym purge i retestem. To pozwala wykazać rzeczywisty wpływ bez ryzyka dla ruchu klientów.

UDOSTĘPNIJ / KOPIUJ