TON (The Open Network) est une plateforme blockchain décentralisée conçue et développée à l'origine par l'équipe Telegram. Elle a attiré l'attention dès son lancement. L'objectif de TON est de fournir une plate-forme blockchain hautes performances et évolutive pour prendre en charge les applications décentralisées (DApps) à grande échelle et les contrats intelligents. Des connaissances de base sur TON peuvent être trouvées dans Apprendre à connaître TON : comptes, jetons, transactions et sécurité des actifs.

Il convient de noter que TON a une architecture complètement différente des autres blockchains. En plus d'utiliser principalement le langage FunC pour la programmation, les contrats intelligents de TON utilisent également le niveau supérieur Tact ou le niveau inférieur Fift. Il s’agit de langages très originaux, il est donc essentiel d’assurer la sécurité des contrats intelligents.

L'équipe de sécurité de SlowMist a intégré et absorbé les pratiques de développement de sécurité partagées par la communauté TON, combinées à sa propre expérience en matière d'audit de sécurité accumulée au fil de nombreuses années, pour publier « Toncoin Smart Contract Security Best Practices », visant à aider les développeurs à mieux comprendre la sécurité de Toncoin. les contrats intelligents.

En raison du manque d'espace, cet article ne répertorie qu'une partie des « Meilleures pratiques de sécurité des contrats intelligents Toncoin ». Vous êtes invités à regarder, fourchette et étoile sur GitHub : https://github.com/slowmist/Toncoin-Smart-Contract-Security. -Meilleures -Pratiques.

Pièges courants des contrats intelligents Toncoin

1. Modificateur impur manquant

  • Gravité : élevée

  • Description : un attaquant peut découvrir que la fonction « autoriser » n'est pas marquée « impure ». L'absence de ce modificateur permettra au compilateur d'ignorer l'appel d'une fonction si elle n'a pas de valeur de retour ou si la valeur de retour n'est pas utilisée.

  • Scénario d'attaque :

  • Recommandation : assurez-vous que la fonction utilise le modificateur "impure".

2. Mauvaise utilisation des méthodes de modification/non-modification

  • Gravité : élevée

  • Description : "udict_delete_get?" a été appelé de manière incorrecte avec "." au lieu de "~", le dictionnaire réel n'a donc pas été modifié.

  • Scénario d'attaque :

  • Recommandation : vérifiez toujours si une méthode est une méthode modificatrice/non modificatrice.

3. Utilisation incorrecte d'entiers signés/non signés

  • Gravité : élevée

  • Description : les droits de vote sont stockés dans le message sous forme d'entiers. Ainsi, un attaquant peut envoyer des valeurs négatives lors d’un transfert de pouvoir et obtenir des droits de vote illimités.

  • Scénario d'attaque :

  • Recommandation : Dans certains scénarios, les entiers non signés sont plus sûrs car ils peuvent générer une erreur en cas de débordement. N'utilisez des entiers signés que lorsque vous en avez vraiment besoin.

4. Nombres aléatoires dangereux

  • Gravité : élevée

  • Description : la valeur de départ est dérivée de l'heure logique de la transaction, et l'attaquant peut gagner en craquant par force brute l'heure logique dans le bloc actuel (car l'heure logique est continue dans les limites d'un bloc).

  • Scénario d'attaque :

  • Recommandation : toujours randomiser la graine avant de faire "rand()", et de préférence ne jamais utiliser de nombres aléatoires en chaîne car le validateur peut contrôler ou influencer la graine.

5. Envoyez des données privées en chaîne

  • Gravité : élevée

  • Description : N'oubliez pas que toutes les données seront stockées sur la blockchain.

  • Scénario d'attaque : le portefeuille est protégé par mot de passe et son hachage est stocké dans les données du contrat. Cependant, la blockchain enregistre tout : le mot de passe apparaît dans l’historique des transactions.

  • Recommandation : n'envoyez pas de données privées en chaîne.

6. Contrôles manquants pour les messages rebondis

  • Gravité : élevée

  • Description : Vault n'a pas renvoyé de message de gestionnaire ou de proxy à la base de données lorsque l'utilisateur a envoyé une demande de « vérification ». Nous pouvons définir "msg_addr_none" comme adresse de récompense dans la base de données car "load_msg_address" le permet. Nous avons demandé une vérification du coffre-fort et la base de données a essayé d'analyser "msg_addr_none" à l'aide de "parse_std_addr", mais l'analyse a échoué. Le message a été renvoyé de la base de données au coffre-fort et l'opération n'était pas « op_not_winner ».

  • Scénario d'attaque : Vault contient le code suivant dans le gestionnaire de messages de la base de données :

  • Recommandation : vérifiez toujours les messages renvoyés, n'oubliez pas les erreurs causées par les fonctions standards, rendez vos conditions aussi strictes que possible.

7. Risque de destruction de compte dans des conditions concurrentielles

8. Évitez d'exécuter du code tiers

  • Gravité : élevée

  • Description : les développeurs n'ont aucun moyen d'exécuter en toute sécurité du code tiers dans les contrats, car CATCH ne peut pas gérer une quantité de gaz insuffisante, et un attaquant n'a qu'à soumettre n'importe quel état du contrat et à provoquer une quantité de gaz insuffisante pour réaliser l'attaque.

  • Scénario d'attaque :

  • Recommandation : évitez d'exécuter du code tiers dans vos contrats.

9. Conflit de nom

  • Gravité : moyenne

  • Description : les variables et fonctions Func peuvent contenir presque tous les caractères juridiques.

  • Scénario d'attaque : "var++", "~bits", "foo-bar+baz" et virgule "," sont tous des noms de variables et de fonctions valides.

  • Recommandation : lors de l'écriture et de la vérification du code Func, vous devez utiliser les outils linter.

10. Vérifiez la valeur du lancer

  • Gravité : moyenne

  • Description : Chaque fois que l'exécution de TVM s'arrête normalement, elle s'arrête avec le code de sortie « 0 » ou « 1 ». Bien que cela se fasse automatiquement, l'exécution de TVM peut être interrompue de manière inattendue si les commandes "throw(0)" ou "throw(1)" renvoient directement les codes de sortie "0" et "1".

  • Scénario d'attaque :

  • Suggestion : N'utilisez pas "0" ou "1" comme valeur de lancement.

11. Lire/écrire le type de données correct

  • Gravité : moyenne

  • Description : Lire la valeur d'une variable inattendue et appeler une méthode sur un type de données qui ne devrait pas avoir une telle méthode (ou dont la valeur de retour n'est pas stockée correctement) est une erreur et ne sera pas ignorée en tant qu'"avertissement" ou "notification". ", Au lieu de cela, le code ne peut pas être récupéré.

  • Scénario d'attaque : gardez à l'esprit que le stockage d'une valeur inattendue peut être acceptable, mais que sa lecture peut entraîner des problèmes. Par exemple, pour les variables entières, le code d'erreur 5 (Entier hors plage attendue) peut être généré.

  • Recommandation : suivez de près le fonctionnement de votre code et ses éventuelles valeurs de retour. N'oubliez pas que le compilateur ne se soucie que du code et de son état initial.

12. Le code du contrat peut être mis à jour

  • Gravité : moyenne

  • Description : TON implémente entièrement le modèle Actor, ce qui signifie que le code du contrat peut être modifié. Le code peut être modifié de manière permanente via l'instruction TVM "SETCODE", ou en réglant le registre de code TVM sur une nouvelle valeur unitaire au moment de l'exécution jusqu'à la fin de l'exécution.

  • Scénario d'attaque : un développeur peu scrupuleux peut mettre à jour le code de manière malveillante pour voler des fonds.

  • Recommandation : Sachez que le code du contrat peut être mis à jour, assurez-vous que toute mise à jour suit des pratiques sûres et utilisez des mécanismes tels qu'un modèle de gouvernance ou une approbation multi-signatures pour apporter des modifications.

13. Transactions et étapes

  • Gravité : moyenne

  • Description : La phase de calcul exécute le code du contrat intelligent puis effectue des opérations (telles que l'envoi de messages, la modification du code, le changement de bibliothèque, etc.). Contrairement aux blockchains basées sur Ethereum, si vous vous attendez à ce que l’envoi d’un message échoue, vous ne verrez pas le code de sortie de la phase de calcul, car le message n’est pas exécuté dans la phase de calcul, mais dans une phase d’exploitation ultérieure.

  • Scénario d'attaque : comportement inattendu lorsqu'un message échoue pendant la phase d'exploitation, conduisant à des hypothèses incorrectes sur l'état de la transaction.

  • Recommandation : Comprenez que chaque transaction comprend jusqu'à cinq phases : phase de stockage, phase de crédit, phase de calcul, phase d'exploitation et phase de rebond.

14. Impossible d'extraire des données d'autres contrats

  • Gravité : moyenne

  • Description : Les contrats sur la blockchain peuvent résider sur différents fragments et être traités par différents validateurs. Par conséquent, les développeurs ne peuvent pas extraire de données d’autres contrats à la demande. La communication est asynchrone et s'effectue par l'envoi de messages.

  • Scénario d'attaque :

  • Recommandation : Concevez une logique contractuelle autour des messages asynchrones et évitez les hypothèses sur la disponibilité des données synchrones.

15. Deux method_id prédéfinis

  • Gravité : moyenne

  • Description : Il existe deux identifiants de méthode prédéfinis : un pour recevoir des messages au sein de la blockchain "(0)", généralement nommé "recv_internal", et l'autre pour recevoir des messages de l'extérieur "(-1)", nommé "recv_external".

  • Scénario d'attaque :

  • Recommandation : utilisez des méthodes telles que "force_chain(to_address)" pour vérifier que l'adresse se trouve sur la bonne chaîne.

16. Utilisez des messages rebondis

  • Gravité : élevée

  • Description : La blockchain TON est asynchrone et les messages n'ont pas besoin d'arriver dans l'ordre. Les messages d'échec doivent être traités correctement.

  • Scénario d'attaque :

  • Recommandation : utilisez toujours des messages rebondis ("0x18") pour gérer correctement les échecs de messages.

17. Protection contre la relecture

  • Gravité : élevée

  • Description : implémentez une protection contre la relecture pour les portefeuilles (contrats qui stockent les fonds des utilisateurs), soit en utilisant des numéros de séquence (« seqno ») pour garantir que les messages ne sont pas traités deux fois, soit en utilisant des identifiants de transaction uniques avec expiration.

  • Scénario d'attaque :

  • Recommandation : utilisez une méthode de protection contre la relecture, telle que des numéros de séquence ou des identifiants uniques de message, pour empêcher les attaques par relecture.

18. Conditions de concurrence pour les messages

  • Gravité : élevée

  • Description : les cascades de messages peuvent être traitées sur plusieurs blocs et un attaquant pourrait démarrer un flux parallèle, provoquant une situation de concurrence critique.

  • Scénario d'attaque : un attaquant peut utiliser les décalages horaires pour manipuler le comportement du contrat.

  • Recommandation : évitez les conditions de concurrence critique en validant l'état à chaque étape et en ne supposant pas de cohérence de l'état dans le flux de messages.

19. Utiliser le mode valeur portée

  • Gravité : élevée

  • Description : Dans les transferts de jetons (par exemple TON Jetton), les soldes doivent être transférés en mode valeur comptable. L'expéditeur soustrait le solde et le destinataire le rajoute ou le renvoie.

  • Scénario d'attaque : s'ils ne sont pas gérés correctement, les soldes Jetton peuvent être manipulés.

  • Recommandation : utiliser le mode valeur reportée pour garantir un transfert de valeur correct.

20. Soyez prudent lors du remboursement des frais de carburant excédentaires

  • Gravité : élevée

  • Description : Si les frais d'essence excédentaires ne sont pas restitués à l'expéditeur, des fonds peuvent s'accumuler dans le contrat au fil du temps. En principe, ce n’est pas terrible, mais c’est une approche sous-optimale. Une fonction pourrait être ajoutée pour effacer les frais excédentaires, mais les contrats populaires comme TON Jetton renverront toujours les messages de frais excédentaires "op::excesses" à l'expéditeur.

21. Vérifier la valeur de retour de la fonction

  • Gravité : élevée

  • Description : Les fonctions renvoient toujours une valeur ou une erreur. Si vous ignorez la vérification de la valeur de retour, cela peut entraîner une erreur logique fatale.

  • Scénario d'attaque :

  • Recommandation : vérifiez toujours la valeur de retour d'une fonction.

22. Recherchez les faux jetons Jetton

  • Gravité : élevée

  • Description : Le jeton Jetton se compose de deux parties : « jetton-minter » et « jetton-wallet ». Si le contrat du coffre-fort n'est pas correctement validé, un attaquant pourrait drainer les fonds du coffre-fort en déposant de faux jetons et en retirant des jetons de valeur.

  • Scénario d'attaque :

  • Recommandation : vérifiez si l'expéditeur envoie de faux jetons Jetton en calculant l'adresse du portefeuille Jetton de l'utilisateur.

écris à la fin

Pour les développeurs, suivre ces bonnes pratiques peut améliorer efficacement la sécurité des contrats intelligents et réduire les risques de sécurité potentiels. Aujourd’hui, avec le développement rapide de la technologie blockchain, la sécurité reste toujours la priorité absolue. On espère que cette bonne pratique pourra aider davantage de développeurs à créer des contrats intelligents sûrs et fiables et à promouvoir le développement sain de la technologie blockchain.

Liens de référence :

[1] https://dev.to/dvlkv/drawing-conclusions-from-ton-hack-challenge-1aep

[2] https://docs.ton.org/develop/smart-contracts/security/ton-hack-challenge-1

[3] https://docs.ton.org/learn/tvm-instructions/tvm-overview

[4] https://docs.ton.org/develop/smart-contracts/messages

[5] https://docs.ton.org/develop/smart-contracts/security/secure-programming

[6] https://docs.ton.org/develop/smart-contracts/security/things-to-focus

Auteur | Johan

Rédactrice | Lisa

Composition |