Vulnérabilité de relecture de signature dans Smart Contract | BlockAudit

Nov 30 2022
Une astuce utile consiste à signer les messages hors chaîne et à avoir un contrat qui exige cette signature avant d'exécuter une fonction. Par exemple, cette technique est utilisée pour : -- réduire le nombre de transactions sur la chaîne - transaction sans gaz, appelée méta transaction Voyons de quoi nous parlons Les chaînes de blocs s'appuient fortement sur les signatures cryptographiques.

Une astuce utile consiste à signer les messages hors chaîne et à avoir un contrat qui exige cette signature avant d'exécuter une fonction.

Par exemple, cette technique est utilisée pour : -
- réduire le nombre de transactions sur la chaîne
- transaction sans gaz, appelée
meta transaction

Voyons de quoi on parle

Les chaînes de blocs dépendent fortement des signatures cryptographiques. Les transactions sont signées avec les clés privées correspondantes, permettant aux expéditeurs des transactions d'être associés à leurs comptes. La comptabilité de la blockchain serait inopérante sans cette fonctionnalité.

Les signatures numériques sont également fréquemment validées directement dans les contrats intelligents Ethereum, permettant à un ou plusieurs vérificateurs d'autoriser des actions en soumettant des signatures hors chaîne ( ou même des signatures générées par un autre contrat intelligent ).

Ceci est fréquemment utilisé dans les coffres-forts multi-signatures ou les contrats de vote pour soumettre plusieurs signatures en même temps ou pour déléguer l'autorisation.
Les attaques par relecture de signature sont une vulnérabilité courante dans de telles implémentations.

La vérification de la signature dans les contrats intelligents est parfois nécessaire pour améliorer la convivialité ou réduire les coûts de gaz. Une implémentation sécurisée devrait empêcher les attaques par relecture de signature.

Par exemple : -
Garder une trace de tous les hachages de messages traités et autoriser uniquement le traitement des nouveaux hachages de messages. Un utilisateur malveillant pourrait attaquer un contrat dépourvu d'un tel contrôle et obtenir un hachage de message envoyé par un autre utilisateur et traité plusieurs fois.

Signatures numériques cryptographiques

Les signatures numériques sont les primitives à clé publique de l'authentification des messages. Dans le monde physique, les signatures manuscrites sont couramment utilisées sur les messages manuscrits ou dactylographiés. Ils sont utilisés pour lier le signataire au message.

Une signature numérique est une valeur cryptographique générée par des données et une clé secrète connue uniquement du signataire.

Modèle de signature numérique

La procédure complète est expliquée en détail dans les points suivants :

Source de l'image : Wikipédia
  • Chaque utilisateur de ce système dispose d'un ensemble de clés publiques et privées.
  • Les paires de clés utilisées pour le chiffrement/déchiffrement et la signature/vérification sont souvent distinctes les unes des autres. La clé publique est appelée clé de vérification et la clé privée est appelée clé de signature.
  • Les données sont envoyées dans la fonction de hachage par le signataire, qui produit le hachage.
  • L'algorithme de signature génère ensuite la signature numérique sur le hachage fourni à l'aide de la valeur de hachage et de la clé de signature. Les données reçoivent une signature et les deux sont ensuite soumises au vérificateur.
  • L'algorithme de vérification est alimenté par le vérificateur avec la signature numérique et la clé de vérification. Le résultat de l'algorithme de vérification est quelque chose d'utile. Sur les données qu'il reçoit, le vérificateur utilise également le même algorithme de hachage pour produire une valeur de hachage.
  • Cette valeur de hachage et les résultats du processus de vérification sont comparés pour vérification. Le vérificateur détermine si la signature numérique est légitime sur la base des résultats de la comparaison.
  • Personne d'autre ne peut utiliser la clé "privée" du signataire pour établir une signature numérique, de sorte que le signataire ne peut plus tard retirer sa signature des données.

La couche de protocole

Seules les transactions avec des signatures valides sont incluses dans les nouveaux blocs, grâce au réseau Ethereum . Pour les transactions, cela offre les attributs de sécurité suivants :

  • Authentification : La signature est utilisée par les nœuds Ethereum pour confirmer que la personne qui signe la transaction est bien le propriétaire de la clé privée connectée à son adresse publique. Par conséquent, les développeurs peuvent être sûrs que msg.sender est authentique.
  • Intégrité : L'intégrité est la condition selon laquelle la transaction n'a pas été modifiée après avoir été signée ; sinon, la signature est nulle.
  • Non-répudiation : La signature d'une transaction et tout changement d'état effectué par le signataire en possession de la clé privée ne peuvent être contestés. La clé privée appartient à l'adresse publique répertoriée dans le champ de .

La même signature peut être utilisée plusieurs fois pour exécuter une fonction. Cela peut être préjudiciable si l'intention du signataire était d'approuver une transaction une seule fois.

Exemple de code

Examinons le bogue.

function unlock(
  address _to,
  uint256 _amount,
  uint8[] _v,
  bytes32[] _r,
  bytes32[] _s
)
  external
{
  require(_v.length >= 20);
  bytes32 hashData = keccak256(_to, _amount);
  for (uint i = 0; i < _v.length; i++) {
    address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
    require(_isValidator(recAddr));
  }
  to.transfer(_amount);
}

Le message qui est signé par les validateurs utilisant la technique ECDSA est l'endroit où se situe le problème avec le code susmentionné. L'adresse du destinataire et l'argent requis sont les seules informations contenues dans le message. Rien dans le message ne peut être utilisé pour éviter d'utiliser la même signature plus d'une fois. Considérez le cas suivant :

  • Sam transfère 2000 ETH du réseau lié vers la chaîne Ethereum en utilisant le même montant de devise.
  • Le traitement de cette transaction cross-blockchain est Tom, un relais. Afin de libérer 2000 ETH du contrat et de l'envoyer à Sam, il rassemble les signatures de validateur requises, verrouille le bon montant sur la chaîne connectée, puis utilise la fonction de déverrouillage.
  • Sur la blockchain, la transaction contenant les tableaux de valeurs de signature est vue par tout le monde.
  • Maintenant que Sam a copié les tableaux de signature, il peut indépendamment soumettre un appel de déverrouillage. Une fois de plus, le processus de déverrouillage sera réussi, entraînant le transfert de 2000 ETH à Sam.
  • Sam est capable de continuer de cette manière jusqu'à ce que le contrat soit épuisé.

Une attaque par relecture de signature est ce qui est décrit dans l'exemple ci-dessus. C'est concevable puisqu'il n'y a aucun moyen de déterminer si ce message signé spécifique est unique ou s'il a déjà été utilisé.

Signez les messages avec nonceet l'adresse du contrat.

public uint256 nonce;
function unlock(
  address _to,
  uint256 _amount, 
  uint256 _nonce,
  uint8[] _v,
  bytes32[] _r,
  bytes32[] _s
)
  external
{
  require(_v.length >= 20);
  require(_nonce == nonce++);
  bytes32 hashData = keccak256(_to, _amount, _nonce);
  for (uint i = 0; i < _v.length; i++) {
    address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
    require(_isValidator(recAddr));
  }
  to.transfer(_amount);
}

Afin de vous protéger contre les attaques par relecture de signature, tenez compte des recommandations suivantes :

  • Stockez chaque hachage de message qui a été traité par le contrat intelligent. Lorsque de nouveaux messages sont reçus, vérifiez-les par rapport à ceux déjà existants et ne procédez à la logique métier que s'il s'agit d'un nouveau hachage de message.
  • Inclure l'adresse du contrat qui traite le message. Cela garantit que le message ne peut être utilisé que dans un seul contrat.
  • Ne générez en aucun cas le hachage du message incluant la signature. La ecrecoverfonction est sensible à la malléabilité de la signature.

Les signatures non uniques peuvent être rejouées dans diverses situations, comme le montre l'exemple ci-dessus. Pour éviter les attaques par répétition, il est crucial dans la majorité des situations de s'assurer que les signatures correspondent spécifiquement à chaque appel. De plus, pour cette raison, un nonce est inclus dans chaque transaction Ethereum.

Références: -

https://solidity-by-example.org/hacks/signature-replay/
https://blog.finxter.com/smart-contract-replay-attack-solidity/
https://swcregistry.io/docs/SWC-121

Bousculer avec la sécurité web3 !!! Connecte-toi avec nous!!!

BlockAudit :- Pourquoi nous ??
BlockAudit possède les ressources et les connaissances nécessaires pour créer des solutions de cybersécurité qui permettent d'économiser des millions de dollars.
Linkedin | Site Web | Twitter