Je voulais simplement partager un problème de sécurité des smart contracts que de nombreux développeurs ont tendance à négliger : l'attaque par reentrancy. Si vous développez un contrat intelligent en Solidity, c’est un aspect que vous devez absolument maîtriser.



En termes simples, la reentrancy se produit lorsqu’un contrat appelle un autre contrat, et que ce dernier peut rappeler le contrat initial pendant qu’il est encore en train d’exécuter. Imaginez que vous avez ContractA contenant 10 Ether et que ContractB envoie 1 Ether vers celui-ci. Lorsqu’il retire de l’argent, ContractA vérifie si le solde est supérieur à 0, puis envoie l’Ether. Cependant, si ContractB possède une fallback function(, elle peut rappeler la fonction de retrait de ContractA pendant que celle-ci n’a pas encore terminé. Résultat ? Le solde de ContractB est toujours enregistré comme 1 Ether, donc il recevra un autre Ether, et ainsi de suite jusqu’à épuisement de ContractA.

Comment fonctionne cette attaque ? L’attaquant a besoin de deux éléments : une fonction attack)( pour démarrer, et une fallback function pour rappeler la fonction de retrait. La fallback function est une fonction spéciale extérieure sans nom, sans paramètres, que n’importe qui peut déclencher en appelant une fonction inexistante, en n’envoyant pas de données, ou en envoyant des Ether sans données.

Un exemple concret : le contrat EtherStore possède une fonction deposit)( qui stocke le solde, et une fonction withdrawAll)( qui retire tout. Le problème est que withdrawAll)( vérifie le solde, envoie l’Ether, puis met à jour le solde à 0. Cela crée une faille pour l’attaque par reentrancy.

Comment s’en protéger ? Je vais vous donner trois méthodes.

Premièrement, utiliser le modifier noReentrant. L’idée est très simple : verrouiller le contrat pendant l’exécution d’une fonction. Si quelqu’un tente de rappeler cette fonction, il doit passer le verrou, mais celui-ci ne sera levé qu’à la fin de l’exécution. Le modifier est une fonction spéciale qui permet d’ajouter une condition à d’autres fonctions sans réécrire toute la logique.

Deuxièmement, appliquer le pattern Check-Effect-Interaction. Au lieu de vérifier la condition, envoyer l’Ether, puis mettre à jour le solde, il faut faire l’inverse : vérifier d’abord, mettre à jour le solde immédiatement)avant de transférer(, puis effectuer l’interaction avec l’extérieur. Ainsi, même si une reentrancy se produit, le solde sera déjà à 0, empêchant l’attaquant de retirer plus.

Troisièmement, si votre projet comporte plusieurs contrats qui interagissent, utilisez GlobalReentrancyGuard. Au lieu de verrouiller une seule fonction, vous verrouillez tout le système avec une variable d’état stockée dans un contrat séparé. Lorsqu’une fonction de n’importe quel contrat est appelée, elle vérifie si le système est verrouillé. Si oui, la transaction est rejetée. Cela est particulièrement utile si vous avez des contrats comme ScheduledTransfer envoyant de l’argent à AttackTransfer — GlobalReentrancyGuard empêchera toute chaîne d’attaques par reentrancy.

Ce qui est intéressant avec ces trois méthodes, c’est qu’elles peuvent être combinées selon la situation. Une fonction critique ? Utilisez noReentrant. Plusieurs fonctions liées ? Appliquez Check-Effect-Interaction. Projet complexe ? Mettez en place GlobalReentrancyGuard. Comprendre la reentrancy et comment la prévenir vous aidera à construire des contrats intelligents beaucoup plus sécurisés.
Voir l'original
Cette page peut inclure du contenu de tiers fourni à des fins d'information uniquement. Gate ne garantit ni l'exactitude ni la validité de ces contenus, n’endosse pas les opinions exprimées, et ne fournit aucun conseil financier ou professionnel à travers ces informations. Voir la section Avertissement pour plus de détails.
  • Récompense
  • Commentaire
  • Reposter
  • Partager
Commentaire
Ajouter un commentaire
Ajouter un commentaire
Aucun commentaire
  • Épingler