Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙ Pengaturan Proxy Target

23 octobre 2022

L'attaque par clickjacking

L’attaque par “clickjacking” permet à une page malveillante de cliquer sur un “site victime” au nom du visiteur.

De nombreux sites ont Ă©tĂ© piratĂ©s de cette maniĂšre, notamment Twitter, Facebook, Paypal et d’autres sites. Ils ont tous Ă©tĂ© rĂ©parĂ©s, bien sĂ»r.

L’idĂ©e

L’idĂ©e est trĂšs simple.

Voici comment le clickjacking a été fait avec Facebook:

  1. Un visiteur est attiré vers la page malveillante. Peu importe comment.
  2. La page contient un lien inoffensif (du type “enrichissez-vous maintenant” ou “cliquez ici, trùs drîle”).
  3. Au-dessus de ce lien, la page malĂ©fique place un <iframe> transparent avec src de facebook.com, de telle sorte que le bouton “J’aime” se trouve juste au-dessus de ce lien. Habituellement, cela se fait avec z-index.
  4. En essayant de cliquer sur le lien, le visiteur clique en fait sur le bouton.

La démo

Voici à quoi ressemble la page malveillante. Pour que les choses soient claires, le <iframe> est semi-transparent (dans les vraies pages maléfiques, il est totalement transparent):

<style>
iframe { /* iframe du site de la victime */
  width: 400px;
  height: 100px;
  position: absolute;
  top:0; left:-20px;
  opacity: 0.5; /* en réalité opacity:0 */
  z-index: 1;
}
</style>

<div>Click to get rich now:</div>

<!-- L'url du site de la victime -->
<iframe src="/clickjacking/facebook.html"></iframe>

<button>Click here!</button>

<div>...And you're cool (I'm a cool hacker actually)!</div>

La dĂ©mo complĂšte de l’attaque:

Résultat
facebook.html
index.html
<!DOCTYPE HTML>
<html>

<body style="margin:10px;padding:10px">

  <input type="button" onclick="alert('Like pressed on facebook.html!')" value="I LIKE IT !">

</body>

</html>
<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
</head>

<body>

  <style>
    iframe {
      width: 400px;
      height: 100px;
      position: absolute;
      top: 5px;
      left: -14px;
      opacity: 0.5;
      z-index: 1;
    }
  </style>

  <div>Click to get rich now:</div>

  <!-- The url from the victim site -->
  <iframe src="facebook.html"></iframe>

  <button>Click here!</button>

  <div>...And you're cool (I'm a cool hacker actually)!</div>

</body>
</html>

Ici, nous avons un <iframe src="facebook.html"> semi-transparent, et dans l’exemple, nous pouvons le voir planer au-dessus du bouton. En cliquant sur le bouton, on clique en fait sur l’iframe, mais l’utilisateur ne le voit pas, car l’iframe est transparent.

Par consĂ©quent, si le visiteur est connectĂ© sur Facebook (l’option “Se souvenir de moi” est gĂ©nĂ©ralement activĂ©e), un bouton “J’aime” est ajoutĂ©. Sur Twitter, ce serait un bouton “Suivre”.

Voici le mĂȘme exemple, mais plus proche de la rĂ©alitĂ©, avec opacity:0 pour <iframe>:

Résultat
facebook.html
index.html
<!DOCTYPE HTML>
<html>

<body style="margin:10px;padding:10px">

  <input type="button" onclick="alert('Like pressed on facebook.html!')" value="I LIKE IT !">

</body>

</html>
<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
</head>

<body>

  <style>
    iframe {
      width: 400px;
      height: 100px;
      position: absolute;
      top: 5px;
      left: -14px;
      opacity: 0;
      z-index: 1;
    }
  </style>

  <div>Click to get rich now:</div>

  <!-- The url from the victim site -->
  <iframe src="facebook.html"></iframe>

  <button>Click here!</button>

  <div>...And you're cool (I'm a cool hacker actually)!</div>

</body>
</html>

Tout ce dont nous avons besoin pour attaquer – c’est de positionner le <iframe> sur la page malveillante de maniĂšre Ă  ce que le bouton soit juste au-dessus du lien. Ainsi, lorsqu’un utilisateur clique sur le lien, il clique en fait sur le bouton. C’est gĂ©nĂ©ralement faisable avec CSS.

Le clickjacking est pour les clics, pas pour le clavier

L’attaque n’affecte que les actions de la souris (ou des actions similaires, comme les tapotements sur les mobiles).

La saisie au clavier est trĂšs difficile Ă  rediriger. Techniquement, si nous avons un champ de texte Ă  pirater, nous pouvons alors positionner un iframe de telle sorte que les champs de texte se chevauchent. Ainsi, lorsqu’un visiteur essaie de se concentrer sur la saisie qu’il voit sur la page, il se concentre en fait sur la saisie Ă  l’intĂ©rieur de l’iframe.

Mais il y a un problĂšme. Tout ce que le visiteur tape sera cachĂ©, car l’iframe n’est pas visible.

Les gens s’arrĂȘtent gĂ©nĂ©ralement de taper lorsqu’ils ne voient pas leurs nouveaux caractĂšres s’imprimer Ă  l’écran.

Défenses de la vieille école (faibles)

La dĂ©fense la plus ancienne est un bout de JavaScript qui interdit l’ouverture de la page dans un iframe (ce qu’on appelle le “framebusting”).

Cela ressemble Ă  ceci:

if (top != window) {
  top.location = window.location;
}

C’est-Ă -dire que si la fenĂȘtre dĂ©couvre qu’elle n’est pas en haut, elle se met automatiquement en haut.

Ce n’est pas une dĂ©fense fiable, car il existe de nombreuses façons de la contourner. En voici quelques-unes.

Blocage de la navigation supérieure

Nous pouvons bloquer la transition provoquĂ©e par le changement de top.location dans l’évĂ©nement beforeunload.

La page du haut (appartenant au pirate) lui attribue un événement de prévention, comme ceci:

window.onbeforeunload = function() {
  return false;
};

Lorsque le iframe essaie de changer top.location, le visiteur reçoit un message lui demandant s’il veut quitter le site.

Dans la plupart des cas, le visiteur rĂ©pondra nĂ©gativement parce qu’il ne connaĂźt pas l’iframe – tout ce qu’il peut voir est la page d’accueil, il n’a aucune raison de la quitter. Donc top.location ne changera pas!

En action:

Résultat
iframe.html
index.html
<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
</head>

<body>

  <div>Changes top.location to javascript.info</div>

  <script>
    top.location = 'https://javascript.info';
  </script>

</body>

</html>
<!doctype html>
<html>

<head>
  <meta charset="UTF-8">

  <style>
    iframe {
      width: 400px;
      height: 100px;
      position: absolute;
      top: 0;
      left: -20px;
      opacity: 0;
      z-index: 1;
    }
  </style>

  <script>
    function attack() {

      window.onbeforeunload = function() {
        window.onbeforeunload = null;
        return "Want to leave without learning all the secrets (he-he)?";
      };

      document.body.insertAdjacentHTML('beforeend', '<iframe src="iframe.html">');
    }
  </script>
</head>

<body>

  <p>After a click on the button the visitor gets a "strange" question about whether they want to leave.</p>

  <p>Probably they would respond "No", and the iframe protection is hacked.</p>

  <button onclick="attack()">Add a "protected" iframe</button>

</body>
</html>

L’attribut Sandbox

L’une des choses limitĂ©es par l’attribut sandbox est la navigation. Une iframe protĂ©gĂ©e par un sandbox ne peut pas modifier l’attribut top.location.

Nous pouvons donc ajouter l’iframe avec sandbox="allow-scripts allow-forms". Cela assouplirait les restrictions, autorisant les scripts et les formulaires. Mais nous omettons allow-top-navigation pour que la modification de top.location soit interdite.

Voici le code:

<iframe sandbox="allow-scripts allow-forms" src="facebook.html"></iframe>

Il existe Ă©galement d’autres moyens de contourner cette simple protection.

X-Frame-Options

L’en-tĂȘte X-Frame-Options cĂŽtĂ© serveur peut autoriser ou interdire l’affichage de la page dans un iframe.

Il doit ĂȘtre envoyĂ© exactement comme un en-tĂȘte HTTP : le navigateur l’ignorera s’il se trouve dans la balise HTML <meta>. Ainsi, <meta http-equiv="X-Frame-Options"...> ne fera rien.

L’en-tĂȘte peut avoir 3 valeurs:

DENY
Ne jamais afficher la page Ă  l’intĂ©rieur d’un iframe.
SAMEORIGIN
Autoriser Ă  l’intĂ©rieur d’un iframe si le document parent a la mĂȘme origine

ALLOW-FROM domain
Autoriser Ă  l’intĂ©rieur d’un iframe si le document parent appartient au domaine donné 

Par exemple, Twitter utilise X-Frame-Options: SAMEORIGIN.

Voici le résultat:

<iframe src="https://twitter.com"></iframe>

Selon votre navigateur, le iframe ci-dessus est soit vide, soit vous avertit que le navigateur ne permet pas de naviguer sur cette page de cette maniĂšre.

Affichage de la fonctionnalité désactivée

L’en-tĂȘte X-Frame-Options a un effet secondaire. Les autres sites ne pourront pas afficher notre page dans un iframe, mĂȘme s’ils ont de bonnes raisons de le faire.

Il existe donc d’autres solutions
 Par exemple, on peut “couvrir” la page avec une <div> avec les styles height : 100% ; width : 100%;, pour qu’elle intercepte tous les clics. Cette <div> doit ĂȘtre retirĂ©e si window == top ou si l’on s’aperçoit que l’on n’a pas besoin de cette protection.

Quelque chose comme ça:

<style>
  #protector {
    height: 100%;
    width: 100%;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 99999999;
  }
</style>

<div id="protector">
  <a href="/" target="_blank">Go to the site</a>
</div>

<script>
  // il y aura une erreur si la fenĂȘtre supĂ©rieure est d'une origine diffĂ©rente
  // mais c'est bon ici
  if (top.document.domain == document.domain) {
    protector.remove();
  }
</script>

La démo:

Résultat
iframe.html
index.html
<!doctype html>
<html>

<head>
  <meta charset="UTF-8">

  <style>
    #protector {
      height: 100%;
      width: 100%;
      position: absolute;
      left: 0;
      top: 0;
      z-index: 99999999;
    }
  </style>

</head>

<body>

<div id="protector">
  <a href="/" target="_blank">Go to the site</a>
</div>

<script>

  if (top.document.domain == document.domain) {
    protector.remove();
  }

</script>

  This text is always visible.

  But if the page was open inside a document from another domain, the div over it would prevent any actions.

  <button onclick="alert(1)">Click wouldn't work in that case</button>

</body>
</html>
<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
</head>
<body>

  <iframe src="iframe.html"></iframe>

</body>
</html>

Attribut de cookie “samesite”

L’attribut de cookie samesite peut Ă©galement prĂ©venir les attaques de clickjacking.

Un cookie avec un tel attribut n’est envoyĂ© Ă  un site web que s’il est ouvert directement, et non par l’intermĂ©diaire d’un iframe ou autre. Plus d’informations dans le chapitre Cookies, document.cookie.

Si le site, tel que Facebook, avait l’attribut samesite dans son cookie d’authentification, comme ceci:

Set-Cookie: authorization=secret; samesite


Ce cookie ne serait donc pas envoyĂ© lorsque Facebook est ouvert dans une iframe depuis un autre site. Donc l’attaque Ă©choue.

L’attribut de cookie samesite n’aura pas d’effet lorsque les cookies ne sont pas utilisĂ©s. Cela peut permettre Ă  d’autres sites Web d’afficher facilement nos pages publiques, non authentifiĂ©es, dans des iframes.

Toutefois, cela peut Ă©galement permettre aux attaques par dĂ©tournement de clics de fonctionner dans quelques cas limitĂ©s. Un site Web de vote anonyme qui empĂȘche les doubles votes en vĂ©rifiant les adresses IP, par exemple, serait toujours vulnĂ©rable au dĂ©tournement de clics parce qu’il n’authentifie pas les utilisateurs Ă  l’aide de cookies.

Résumé

Le dĂ©tournement de clics est un moyen de “tromper” les utilisateurs en les incitant Ă  cliquer sur un site victime sans mĂȘme savoir ce qui se passe. C’est dangereux s’il y a des actions importantes activĂ©es par le clic.

Un hacker peut poster un lien vers sa page malveillante dans un message, ou attirer les visiteurs sur sa page par d’autres moyens. Il existe de nombreuses variantes.

D’un certain point de vue, l’attaque n’est “pas profonde” : le pirate ne fait qu’intercepter un seul clic. Mais d’un autre point de vue, si le pirate sait qu’aprĂšs le clic, un autre contrĂŽle apparaĂźtra, il peut utiliser des messages astucieux pour contraindre l’utilisateur Ă  cliquer Ă©galement sur ces contrĂŽles.

Cette attaque est assez dangereuse, car lorsque nous concevons l’interface utilisateur, nous ne prĂ©voyons gĂ©nĂ©ralement pas qu’un pirate puisse cliquer au nom du visiteur. Les vulnĂ©rabilitĂ©s peuvent donc se trouver dans des endroits totalement inattendus.

  • Il est recommandĂ© d’utiliser X-Frame-Options : SAMEORIGIN sur les pages (ou les sites entiers) qui ne sont pas destinĂ©es Ă  ĂȘtre affichĂ©es dans des iframes.
  • Utilisez une couverture <div> si nous voulons permettre Ă  nos pages d’ĂȘtre affichĂ©es dans des iframes, tout en restant sĂ©curisĂ©es.
Carte du tutoriel

Commentaires

lire ceci avant de commenter

  • Si vous avez des amĂ©liorations Ă  suggĂ©rer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
  • Si vous ne comprenez pas quelque chose dans l'article, merci de prĂ©ciser.
  • Pour insĂ©rer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes – enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen
)