Futures
Accédez à des centaines de contrats perpétuels
TradFi
Or
Une plateforme pour les actifs mondiaux
Options
Hot
Tradez des options classiques de style européen
Compte unifié
Maximiser l'efficacité de votre capital
Trading démo
Introduction au trading futures
Préparez-vous à trader des contrats futurs
Événements futures
Participez aux événements et gagnez
Demo Trading
Utiliser des fonds virtuels pour faire l'expérience du trading sans risque
Lancer
CandyDrop
Collecte des candies pour obtenir des airdrops
Launchpool
Staking rapide, Gagnez de potentiels nouveaux jetons
HODLer Airdrop
Conservez des GT et recevez d'énormes airdrops gratuitement
Launchpad
Soyez les premiers à participer au prochain grand projet de jetons
Points Alpha
Tradez on-chain et gagnez des airdrops
Points Futures
Gagnez des points Futures et réclamez vos récompenses d’airdrop.
Investissement
Simple Earn
Gagner des intérêts avec des jetons inutilisés
Investissement automatique
Auto-invest régulier
Double investissement
Profitez de la volatilité du marché
Staking souple
Gagnez des récompenses grâce au staking flexible
Prêt Crypto
0 Fees
Mettre en gage un crypto pour en emprunter une autre
Centre de prêts
Centre de prêts intégré
Comprendre en profondeur les attaques par réentrance et les moyens de défense efficaces
## Qu'est-ce que la réentrance ?
La réentrance est une vulnérabilité critique dans les contrats intelligents où une fonction peut être appelée à plusieurs reprises avant que l'exécution précédente ne soit terminée. Un attaquant exploite ce comportement pour extraire des fonds ou manipuler l'état du contrat.
## Mécanisme d'attaque classique
1. **Appel initial** : L'attaquant effectue un dépôt ou une transaction légitime
2. **Exploitation** : Grâce à une fonction de rappel, le contrat attaquant relance le retrait plusieurs fois
3. **Drainage** : Les fonds sont extraits plusieurs fois avec le même solde
4. **Échec de mise à jour** : L'état du contrat n'est pas mis à jour avant les appels externes
## Exemple vulnérable
```solidity
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount);
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] -= amount;
}
```
## Stratégies de défense
### 1. Vérifier-Effectuer-Intéragir (Checks-Effects-Interactions)
```solidity
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
```
### 2. Utiliser un mutex (Verrou de réentrance)
```solidity
bool private locked;
modifier nonReentrant() {
require(!locked);
locked = true;
_;
locked = false;
}
function withdraw(uint amount) public nonReentrant {
require(balances[msg.sender] >= amount);
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] -= amount;
}
```
### 3. OpenZeppelin ReentrancyGuard
```solidity
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SecureContract is ReentrancyGuard {
function withdraw(uint amount) public nonReentrant {
// Logique de retrait sécurisée
}
}
```
## Cas d'usage réels
### The DAO (2016)
- **Perte** : 3,6 millions d'ETH
- **Cause** : Réentrance classique dans la fonction de retrait
- **Impact** : Fork d'Ethereum, création d'Ethereum Classic
### Curve Finance (2023)
- **Faille** : Réentrance croisée entre contrats
- **Montant** : ~24 millions de dollars
- **Solution** : Audit approfondi et correctifs
## Meilleures pratiques
1. **Audits de sécurité** : Faire examiner le code par des experts
2. **Tests unitaires** : Vérifier les scénarios de réentrance
3. **Standards de codage** : Utiliser les patterns éprouvés
4. **Limites de gaz** : Implémenter des seuils de dépense
5. **Mise à jour d'état en premier** : Toujours avant les appels externes
6. **Utiliser des bibliothèques** : OpenZeppelin, SafeTransferLib
## Outils de détection
- **Slither** : Analyseur statique pour Solidity
- **Mythril** : Analyse symbolique des bytecode
- **MythX** : Plateforme d'analyse de sécurité
- **Manticore** : Outil d'exécution symbolique
La maîtrise de la réentrance est essentielle pour développer des contrats intelligents sécurisés et protéger les actifs numériques des utilisateurs.
Les attaques par reentrancy sont l’une des menaces de sécurité les plus graves pour les smart contracts. Cet article vous expliquera non seulement comment fonctionne la reentrancy, mais aussi comment protéger votre projet de manière complète.
Pour une compréhension approfondie, nous commencerons par les concepts de base, analyserons le code source d’attaques réelles, puis explorerons trois techniques de prévention éprouvées : du modifier nonReentrant() à GlobalReentrancyGuard() et le pattern check-effect-interaction.
Qu’est-ce qu’une attaque de type reentrancy ?
Imaginez deux smart contracts interagissant. ContractA et ContractB peuvent s’appeler mutuellement. Cela peut sembler normal, mais c’est justement cette capacité qui peut être exploitée par un attaquant.
Le concept clé de la reentrancy est : un smart contract peut rappeler un autre contrat pendant son exécution. Cela peut créer une boucle infinie si ce comportement n’est pas contrôlé.
Pour illustrer, considérons la situation suivante : ContractA détient 10 Ether, dont ContractB a envoyé 1 Ether. Normalement, lorsque ContractB demande un retrait, il vérifie (solde > 0), reçoit l’Ether, puis son solde est mis à zéro. Mais avec reentrancy, cette étape peut être répétée plusieurs fois avant que le solde ne soit mis à jour.
Mécanisme d’une attaque de type Reentrancy
L’attaquant a besoin de deux éléments principaux : une fonction attack() et une fonction fallback().
La fonction fallback est une fonction spéciale en Solidity — une fonction externe sans nom, sans paramètres et sans valeur de retour. Elle s’active automatiquement lorsque :
Voici comment l’attaque se déroule étape par étape :
Étape 1 : L’attaquant appelle attack(), qui à son tour appelle la fonction de retrait dans ContractA.
Étape 2 : ContractA vérifie si le solde de ContractB est supérieur à zéro. C’est le cas, il envoie 1 Ether à ContractB et active la fonction fallback.
Étape 3 : C’est le moment critique — le solde n’a pas encore été mis à zéro. ContractA continue d’exécuter la fonction de retrait.
Étape 4 : La fallback est activée et rappelle immédiatement la fonction de retrait de ContractA.
Étape 5 : ContractA vérifie à nouveau — le solde de ContractB est toujours de 1 Ether (la mise à jour n’a pas encore été faite). Il envoie encore 1 Ether et réactive fallback.
Ce processus se répète jusqu’à ce que ContractA ait vidé tous ses Ether. C’est pourquoi la reentrancy est si dangereuse.
Analyse du code d’attaque spécifique
Pour mieux comprendre, prenons un exemple avec le smart contract EtherStore. Ce contrat possède deux fonctions principales :
La fonction withdrawAll() suit l’ordre : vérification (solde > 0), envoi d’Ether, puis mise à zéro du solde.
C’est cette séquence qui présente une vulnérabilité. L’envoi d’Ether se produit avant la mise à jour, permettant à l’attaquant d’intervenir.
Le contrat Attack est conçu pour exploiter cette faille. Il possède :
Le processus d’attaque est simple :
Trois techniques pour prévenir les attaques de type Reentrancy
Technique 1 : Utiliser le modifier nonReentrant
La méthode la plus simple pour protéger une seule fonction est d’utiliser le modifier nonReentrant. Un modifier est une sorte de wrapper en Solidity qui ajoute des conditions ou fonctionnalités à une fonction sans en réécrire la logique.
Fonctionnement de nonReentrant :
Inconvénients : nonReentrant ne protège qu’une seule fonction, il ne couvre pas les attaques de reentrancy croisées entre différentes fonctions.
Technique 2 : Pattern check-effect-interaction
C’est une méthode plus avancée pour protéger plusieurs fonctions. Au lieu de verrouiller le contrat, on change l’ordre d’exécution du code.
Ce pattern exige :
Comparer deux versions de code :
En mettant à jour le solde juste après la vérification, même si une reentrancy se produit, le solde sera déjà à jour, empêchant l’attaque.
Technique 3 : GlobalReentrancyGuard pour plusieurs contrats
Cette technique s’adresse aux projets avec plusieurs smart contracts interconnectés. L’idée est de créer un contrat central qui contrôle la reentrancy sur tout le système.
Au lieu que chaque contrat ait sa propre variable de verrou, tous font référence à un GlobalReentrancyGuard. Cela permet :
Exemple pratique : si ScheduledTransfer envoie des Ether à AttackTransfer, la fallback d’AttackTransfer peut tenter de rappeler d’autres fonctions dans ScheduledTransfer. GlobalReentrancyGuard détecte et bloque cela.
Choisir la bonne technique de prévention
Utiliser nonReentrant quand :
Utiliser check-effect-interaction quand :
Utiliser GlobalReentrancyGuard quand :
Il est souvent judicieux de combiner ces techniques selon les besoins spécifiques de votre projet.
Conclusion
Les attaques de reentrancy ne sont pas insurmontables si vous comprenez leur fonctionnement et appliquez les bonnes techniques. Du simple modifier nonReentrant à la solution globale GlobalReentrancyGuard, chaque outil a son rôle dans la sécurité des smart contracts.
Souvenez-vous : la sécurité n’est pas une option, c’est une nécessité. En comprenant ces attaques et en déployant des protections adaptées, vous pouvez construire des smart contracts à la fois sûrs et performants.
Pour suivre l’actualité en sécurité Web3, Solidity, audit de smart contracts et autres sujets, suivez @TheBlockChainer sur Twitter.