Attaque Reentrancy : Prévenir la Reentrancy en Solidity

Article author

Les attaques de réentrance restent l’une des menaces les plus notoires et persistantes pour la sécurité des smart contracts sur Ethereum et les chaînes compatibles EVM. Malgré des années d’efforts dans l’industrie, de nouveaux protocoles continuent de présenter des vulnérabilités de réentrance, entraînant des pertes financières significatives—parfois atteignant des millions de dollars. Ces exploits apparaissent souvent dans les contrats DeFi de prêt, de staking et de ponts, où les appels externes et les transferts de tokens sont courants.

Dans cet article, nous disséquons la mécanique d’une attaque de réentrance, identifions les modèles typiques de contrats vulnérables, et partageons des stratégies de mitigation éprouvées. À partir de notre analyse de plus de 282 audits de smart contracts chez Soken, nous mettons en lumière comment des pratiques de codage Solidity nuancées et des workflows de test complets peuvent contrecarrer les menaces de réentrance. Ce document relie également ces risques à des problématiques connexes telles que l’usage abusif de delegatecall et les tactiques de flash loan pour fournir une compréhension globale essentielle à tout développeur Web3 ou auditeur de sécurité sérieux.


Qu’est-ce qu’une attaque de réentrance et comment exploite-t-elle les smart contracts ?

Une attaque de réentrance se produit lorsqu’un contrat malveillant appelle de manière répétée une fonction d’un contrat vulnérable avant que l’exécution initiale ne soit terminée, exploitant ainsi l’état incohérent du contrat.

En pratique, une vulnérabilité de réentrance découle de changements d’état mal ordonnés et d’appels externes à l’intérieur d’un contrat. Lorsque le contrat transfère de l’ETH ou des tokens via un call ou un transfer vers une adresse non fiable, le destinataire peut ré-entrer de manière récursive dans la fonction vulnérable avant que les variables d’état ne soient mises à jour. Cela permet à l’attaquant de vider les fonds ou de manipuler la logique du contrat de façon inattendue.

Par exemple, le célèbre hack du DAO en 2016 a abouti à l’exploitation d’environ 60 millions de dollars via des failles de réentrance — une leçon à méditer. Depuis, l’industrie a identifié que la cause racine est la mise à jour du solde ou de l’état du contrat qui n’intervient qu’après les appels externes, créant ainsi une fenêtre d’état incohérent exploitée par l’attaquant.

Insight d’experts issus des audits Soken : « Dans plus de 40 % de nos récents audits de sécurité DeFi, des schémas de réentrance apparaissent sous diverses formes, souvent des variations subtiles impliquant des contrats proxy ou des appels en cascade. Les identifier nécessite une analyse approfondie des appels inter-contrats au-delà d’une inspection contractuelle unique. »


Modèles Solidity courants qui causent des vulnérabilités de réentrance

Les vulnérabilités de réentrance résultent typiquement d’une séquence spécifique d’opérations : des appels externes (comme les transferts ETH ou tokens) qui interviennent avant que le contrat ne mette à jour ses variables d’état internes.

Le schéma le plus vulnérable ressemble à ceci :

function withdraw(uint256 amount) public {
    require(balances[msg.sender] >= amount);
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
    balances[msg.sender] -= amount;
}

Ici, l’appel externe utilisant call.value() se produit avant la déduction du solde de l’utilisateur. Lors de cet appel externe, la fonction de fallback d’un attaquant peut invoquer récursivement withdraw(), vidant ainsi les fonds avant la mise à jour des soldes.

Parmi les constructions risquées clés, on trouve :

  • Appels externes avant mises à jour d’état : Envoi d’ETH ou de tokens avant de mettre à jour les soldes.
  • Utilisation de call ou send sans précautions : L’appel externe via des fonctions de bas niveau contourne les contrôles et peut invoquer des fonctions fallback.
  • Absence de garde anti-réentrance : Pas de mutex ou autres mécanismes de verrouillage.
  • Chaînes d’appels complexes avec delegatecall : Ces dernières peuvent indirectement ouvrir la porte à la réentrance via des appels externes dans les contrats appelés.

À l’inverse, le schéma plus sûr inverse l’ordre :

function withdraw(uint256 amount) public {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;  // mise à jour d’état en premier
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
}

Comment prévenir les attaques de réentrance en Solidity : bonnes pratiques et outils

La défense la plus efficace contre la réentrance est de mettre à jour l’état avant les appels externes combinée à des motifs explicites de protection contre la réentrance.

Techniques courantes de mitigation :

  1. Pattern Checks-Effects-Interactions :
    Toujours mettre à jour l’état interne avant d’effectuer des appels externes. Cela minimise l’état incohérent du contrat durant les appels externes.

  2. Gardes anti-réentrance / Mutex :
    Le ReentrancyGuard de Solidity issu d’OpenZeppelin utilise un mutex simple pour bloquer les appels imbriqués. On l’intègre ainsi :

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract SecureContract is ReentrancyGuard {
    mapping(address => uint256) balances;

    function withdraw(uint256 amount) public nonReentrant {
        require(balances[msg.sender] >= amount);
        balances[msg.sender] -= amount;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success);
    }
}
  1. Limiter les appels externes :
    Réduire au minimum les transferts ou interactions dans les fonctions critiques — privilégier les paiements en mode pull où les utilisateurs retirent explicitement leurs fonds.

  2. Analyse statique et outils automatisés :
    Des outils comme Slither et les frameworks d’audit de Soken détectent les vulnérabilités de réentrance.

  3. Utiliser les dernières versions de Solidity et fonctionnalités :
    Solidity 0.8+ intègre des vérifications automatiques d’overflow, mais les risques de réentrance persistent, d’où la nécessité de combiner sécurité du code et patterns robustes.

Méthodologie Soken : Nos audits intègrent modélisation manuelle des menaces, exécution symbolique et fuzzing, permettant de détecter des flux de réentrance complexes souvent manqués par les scanners génériques.


Exemples réels d’exploits de réentrance et leur impact

Les attaques de réentrance restent courantes malgré une sensibilisation accrue. Voici un tableau comparatif de hacks notables illustrant la diversité et le coût de ces exploits :

Incident Date Montant de la perte Schéma exploité Leçon clé
Le hack du DAO 2016-06 ~60 millions $ Réentrance dans la proposition splitDAO Mettre à jour l’état avant appel externe
Le hack de Lendf.Me 2020-04 25 millions $+ Réentrance amplifiée par flash loan Combiner garde anti-réentrance + résilience flash loan
Hack Euler Finance 2023-03 197 millions $ Réentrance imbriquée + delegatecall Les chaînes d’appels complexes augmentent le risque
Hack récent de pont DeFi 2025-11 15 millions $ Exploit de réentrance via transfert de tokens Auditer les interactions inter-contrats

Remarque : Les audits Soken insistent sur une sécurité multi-couches, notamment autour des appels inter-contrats et des standards token qui peuvent déclencher dynamiquement des fonctions fallback.


Delegatecall et vecteurs de flash loan : amplifier les risques de réentrance

Delegatecall, qui exécute du code dans le contexte du contrat appelant, peut obscurcir les risques de réentrance et élargir la surface d’attaque, surtout combiné aux flash loans.

Les attaques de réentrance exploitent souvent les flash loans pour maximiser le capital destiné au vidage récursif :

  • Les flash loans fournissent une grande liquidité immédiate en une seule transaction.
  • Un attaquant utilise ces fonds flash-loanés pour déclencher des appels réentrants afin de vider la liquidité du protocole avant de rembourser le prêt.
  • L’usage de delegatecall peut involontairement activer du code externe non fiable modifiant l’état du contrat ou permettant des réentrées.

Insight sécurité : « Dans l’expérience Soken, la mitigation de la réentrance dépasse les contrats uniques pour englober la conception du protocole — en particulier quand delegatecall et flash loans cohabitent. Les contrats doivent combiner garde anti-réentrance avec validation d’entrée et contrôles spécifiques aux flash loans (plafonds de montant, limites sur les appels récurrents). »


Tableau comparatif : techniques courantes pour prévenir la réentrance

Technique Description Avantages Inconvénients Usage
Checks-Effects-Interactions Mettre à jour état avant appels externes Simple, efficace Nécessite de la rigueur Pratique de sécurité de base
Garde anti-réentrance (mutex) Modifier Solidity pour éviter la réentrée Bloque explicitement les appels récursifs Ajoute un léger coût en gas Recommandé pour toutes les fonctions de retrait
Pattern Pull Payment Laisser les utilisateurs retirer volontairement Minimise le risque de transfert automatique Nécessite une interaction utilisateur Idéal pour contrats d’entiercement et staking
Analyse statique et dynamique Audits automatisés et manuels Détecte les vulnérabilités tôt Peut manquer des flux cross-contract complexes Essentiel pour la garantie avant déploiement
Vérification Flash Loan & Delegatecall Valider l’appelant et le contexte transactionnel Empêche la réentrance amplifiée par prêt flash Complexe à implémenter Critique dans les protocoles DeFi utilisant des prêts

Exemple de code Solidity : un contrat vulnérable à la réentrance et sa correction

Voici un contrat minimalement vulnérable et sa version renforcée avec garde anti-réentrance :

// Vulnérable : retrait avant la mise à jour du solde
contract Vulnerable {
    mapping(address => uint256) public balances;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) external {
        require(balances[msg.sender] >= amount, "Insufficient funds");
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        balances[msg.sender] -= amount; // Vulnérable : état mis à jour après l’appel externe
    }
}

Corrigé avec ReentrancyGuard d’OpenZeppelin et effets avant interaction :

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract Secure is ReentrancyGuard {
    mapping(address => uint256) public balances;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) external nonReentrant {
        require(balances[msg.sender] >= amount, "Insufficient funds");
        balances[msg.sender] -= amount; // État mis à jour avant l’appel externe
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

Astuce pro : Combinez toujours le pattern checks-effects-interactions avec des gardes anti-réentrance. Auditer les graphes d’appels contractuels et tester avec des outils de fuzzing permet de révéler des vulnérabilités de réentrance multi-sauts subtiles avant le déploiement.


Les vulnérabilités de réentrance restent une menace critique pour les smart contracts, en particulier dans les écosystèmes DeFi complexes utilisant flash loans et delegatecall. Les défenses les plus efficaces allient discipline de codage (checks-effects-interactions), gardes explicites, audits rigoureux et validation transactionnelle contextuelle.

Chez Soken, notre recherche en sécurité intègre des techniques manuelles et automatisées affinées à partir de plus de 282 audits de smart contracts, identifiant et remédiant systématiquement la réentrance et les risques associés. S’appuyer sur les meilleures pratiques et des méthodologies de test approfondies est impératif pour tout projet manipulant des fonds utilisateurs.


Besoin d’un accompagnement expert en sécurité ? L’équipe d’auditeurs Soken a passé en revue plus de 255 smart contracts et sécurisé plus de 2 milliards de dollars de valeur protocolaire. Que vous ayez besoin d’un audit complet, d’une évaluation gratuite X-Ray de sécurité, ou d’aide pour naviguer dans les régulations crypto, nous sommes prêts à vous assister.

Parlez à un expert Soken | Consultez nos rapports d’audit

Article author

Questions fréquemment posées

Qu'est-ce qu'une attaque de reentrancy dans les smart contracts ?

Une attaque de reentrancy survient lorsqu'un contrat malveillant rappelle plusieurs fois le contrat victime avant la fin de la première invocation, exploitant les appels externes pour vider des actifs ou modifier l'état de manière imprévue.

Quels modèles de smart contracts sont les plus vulnérables à la reentrancy ?

Les contrats effectuant des appels externes, comme les transferts de tokens ou l’appel d'autres contrats, avant de mettre à jour leur état interne, sont très vulnérables au risque de réentrée récursive durant ces appels.

Comment prévenir les vulnérabilités de reentrancy en Solidity ?

Les méthodes courantes incluent le pattern Checks-Effects-Interactions, l'utilisation du modificateur 'ReentrancyGuard' d'OpenZeppelin, et la réduction des appels externes ou l’implémentation des paiements pull plutôt que push.

Quels outils permettent de détecter les vulnérabilités de reentrancy avant le déploiement ?

Des analyseurs automatisés comme MythX, Slither et Securify détectent les patterns de reentrancy. De plus, des audits manuels approfondis et des tests fuzz améliorent la détection des failles.

Delegatecall et flash loans sont-ils liés aux attaques de reentrancy ?

Oui, une mauvaise utilisation de delegatecall peut permettre des exploits de reentrancy en exécutant du code dans le contexte d’un autre contrat. Les flash loans peuvent amplifier l’impact des attaques, même s’ils ne sont pas des reentrancy en eux-mêmes.

Chat