Garden of KnowledgeApplied Sciences › Computer Science › Software › Security › Web Security
March 22, 2026

Clickjacking et UI Redressing

Le clickjacking (ou UI redressing) est une attaque qui trompe l’utilisateur en lui faisant cliquer sur des éléments d’une page qu’il ne voit pas, superposés sous une interface apparemment anodine.

Principe§

<!-- Page de l'attaquant -->
<html>
<body>
  <!-- Interface visible : jeu ou formulaire innocent -->
  <div style="position: absolute; z-index: 1;">
    <p>Cliquez ici pour gagner un cadeau !</p>
    <button style="position: absolute; top: 150px; left: 200px;">CLIQUER</button>
  </div>

  <!-- Iframe invisible par-dessus : la vraie cible -->
  <iframe
    src="https://banque.com/virement?montant=500&dest=attaquant"
    style="opacity: 0;          /* invisible */
           position: absolute;
           z-index: 2;          /* au-dessus de l'interface visible */
           top: 100px;
           left: 150px;
           width: 300px;
           height: 200px;">
  </iframe>
</body>
</html>

La victime pense cliquer sur le bouton du jeu, mais clique en réalité sur le bouton “Confirmer le virement” de la banque, chargée dans l’iframe invisible.

Variantes§

Likejacking§

<!-- Faire liker une page Facebook sans que l'utilisateur le sache -->
<iframe src="https://facebook.com/plugins/like.php?href=page_attaquant"
        style="opacity: 0; position: absolute; ...">
</iframe>

Cursorjacking§

Remplacer le curseur de la souris par un curseur décalé : l’utilisateur voit son curseur à un endroit mais clique à un autre endroit réel.

Filejacking§

<!-- Forcer un clic sur "input type=file" pour ouvrir le sélecteur de fichiers -->
<!-- Puis piéger l'utilisateur pour qu'il glisse un fichier sensible -->
<input type="file" style="opacity: 0; position: absolute; ..." />

Drag-and-drop jacking§

Exploite les événements drag-and-drop pour faire glisser du contenu sensible (token, fichier) vers un contrôle contrôlé par l’attaquant.

Multi-step clickjacking§

Étape 1 : Clique ici → désactive l'authentification 2FA
Étape 2 : Clique ici → confirme le changement d'email
Étape 3 : Clique ici → confirme avec le bouton final
→ Compte compromis en 3 clics "innocents"

Conditions requises§

Pour qu’une page soit vulnérable au clickjacking :

  1. La cible doit être embeddable dans un <iframe> (pas de X-Frame-Options)
  2. L’action sensible ne doit pas nécessiter de saisie clavier
  3. L’action sensible doit être possible depuis un compte authentifié (cookies envoyés dans l’iframe)

Test de vulnérabilité§

# Vérifier les en-têtes HTTP
curl -I https://site.com | grep -i "x-frame-options\|content-security-policy"

# Si aucun des deux n'est présent → potentiellement vulnérable

# Test HTML rapide
cat > test.html << 'EOF'
<html><body>
<iframe src="https://site.com/page-sensible" width="800" height="600"></iframe>
</body></html>
EOF
# Ouvrir dans le navigateur : si la page s'affiche dans l'iframe → vulnérable
# Script de test automatisé
import requests

def check_clickjacking(url):
    r = requests.get(url)
    xfo = r.headers.get('X-Frame-Options', '').upper()
    csp = r.headers.get('Content-Security-Policy', '')

    if not xfo and 'frame-ancestors' not in csp:
        print(f"VULNERABLE: {url}")
        print("  Aucune protection contre le clickjacking")
    elif xfo in ('DENY', 'SAMEORIGIN'):
        print(f"PROTECTED (X-Frame-Options: {xfo}): {url}")
    elif 'frame-ancestors' in csp:
        print(f"PROTECTED (CSP frame-ancestors): {url}")
    else:
        print(f"WEAK ({xfo}): {url}")

Relation avec CSRF§

Le clickjacking peut contourner les protections CSRF dans certains cas :

CSRF token présent → clickjacking peut quand même fonctionner
(si l'action peut être déclenchée par un seul clic)

Cookie SameSite=Strict → protège contre CSRF et réduit l'impact du clickjacking
(mais pas une protection absolue si le site est en même domaine)

Contre-mesures§

X-Frame-Options (ancien, mais encore largement supporté)§

X-Frame-Options: DENY           # Aucun iframe autorisé
X-Frame-Options: SAMEORIGIN     # Iframe autorisé uniquement depuis le même domaine
X-Frame-Options: ALLOW-FROM https://partenaire.com  # Déprécié, non supporté partout
# Flask
@app.after_request
def set_xframe_options(response):
    response.headers['X-Frame-Options'] = 'DENY'
    return response

# Django (dans settings.py)
X_FRAME_OPTIONS = 'DENY'

Content Security Policy — frame-ancestors (recommandé)§

Plus flexible et moderne que X-Frame-Options.

Content-Security-Policy: frame-ancestors 'none';
Content-Security-Policy: frame-ancestors 'self';
Content-Security-Policy: frame-ancestors 'self' https://partenaire.com;
# Flask — CSP complet
response.headers['Content-Security-Policy'] = (
    "default-src 'self'; "
    "frame-ancestors 'none';"  # Aucun embedding autorisé
)

Frame busting JavaScript (déprécié et contournable)§

// Technique ancienne — ne pas utiliser seule
if (top !== self) {
    top.location = self.location;
}

// Facilement contournée avec l'attribut sandbox de l'iframe
<iframe src="cible.com" sandbox="allow-scripts">
// allow-scripts sans allow-top-navigation → le frame busting échoue

Attribut sandbox (côté intégrateur)§

<!-- Si vous devez embarquer du contenu tiers de manière sécurisée -->
<iframe src="https://partenaire.com/widget"
        sandbox="allow-scripts allow-same-origin"
        <!-- sans allow-forms → les formulaires ne peuvent pas être soumis -->
        <!-- sans allow-top-navigation → ne peut pas rediriger la page parente -->
>
</iframe>

Impact et reporting§

Le clickjacking seul est souvent “medium” en bug bounty. Il monte en criticité quand :

Preuves à fournir dans un rapport :

<!-- PoC minimal à fournir -->
<html>
<body style="background:grey;">
<p>Clickjacking PoC — [Nom Entreprise] — [Date]</p>
<p>La cible est chargée dans une iframe ci-dessous (normalement opacity:0)</p>
<iframe src="https://cible.com/action-sensible"
        style="opacity:0.5; border:2px solid red;"
        width="600" height="400">
</iframe>
</body>
</html>
—The Gardener