
De la risque à la protection : vulnérabilités de sécurité des contrats intelligents TON et recommandations d'optimisation
TechFlow SélectionTechFlow Sélection

De la risque à la protection : vulnérabilités de sécurité des contrats intelligents TON et recommandations d'optimisation
Cet article analysera en détail certaines fonctionnalités liées aux contrats intelligents sur la blockchain TON, ainsi que les failles fréquemment négligées des contrats intelligents sur TON.
Rédaction : Beosin
Dans le contexte du développement rapide de la technologie blockchain, TON (The Open Network), en tant que plateforme blockchain efficace et flexible, attire de plus en plus l'attention des développeurs. L'architecture unique et les caractéristiques de TON offrent des outils puissants et de nombreuses possibilités pour le développement d'applications décentralisées.
Cependant, avec l'augmentation des fonctionnalités et de la complexité, la sécurité des contrats intelligents devient de plus en plus cruciale. FunC, langage de programmation des contrats intelligents sur TON, est réputé pour sa flexibilité et son efficacité, mais il comporte également de nombreux risques et défis potentiels. Pour écrire des contrats intelligents sécurisés et fiables, les développeurs doivent comprendre profondément les spécificités du langage FunC ainsi que les risques associés.
Cet article analyse en détail certaines caractéristiques liées aux contrats intelligents sur la blockchain TON, ainsi que les vulnérabilités souvent négligées dans ces contrats.

Analyse des caractéristiques asynchrones et du mécanisme des comptes sur TON
Appel asynchrone des contrats intelligents
Fractionnement du réseau et communication asynchrone
La blockchain TON est conçue autour de trois types de chaînes : la chaîne principale (Masterchain), les chaînes de travail (Workingchains) et les chaînes de shard (Shardchains).
La chaîne principale constitue le cœur du réseau ; elle stocke les métadonnées globales et gère le mécanisme de consensus. Elle enregistre l'état de toutes les chaînes de travail et de shard, garantissant ainsi la cohérence et la sécurité du réseau entier. Les chaînes de travail sont des blockchains indépendantes, au nombre maximal de 2^32, chargées de traiter des transactions spécifiques et des contrats intelligents. Chaque chaîne de travail peut avoir ses propres règles et fonctionnalités afin de répondre à différents besoins applicatifs. Les chaînes de shard sont des sous-chaînes des chaînes de travail, utilisées pour diviser davantage la charge de traitement, améliorer la capacité de traitement et l'extensibilité. Chaque chaîne de travail peut être divisée en jusqu'à 2^60 chaînes de shard, chacune traitant indépendamment une partie des transactions, permettant ainsi un traitement parallèle très efficace.
Théoriquement, chaque compte peut occuper entièrement une chaîne de shard. Chaque compte gère individuellement son solde en COIN/TOKEN, et les transactions entre comptes peuvent être entièrement parallélisées. La communication entre comptes s'effectue via des messages asynchrones, dont le chemin de transmission entre les shards suit log_16(N) - 1, où N représente le nombre total de shards.

Source de l'image : https://frontierlabzh.medium.com/ton-web3-world-weixin-e1d3ae3b3574
Sur TON, les contrats intelligents interagissent en envoyant et en recevant des messages. Ces messages peuvent être des messages internes (généralement échangés entre contrats intelligents) ou des messages externes (envoyés depuis une source externe). Le processus de transmission ne nécessite pas d'attendre une réponse immédiate du contrat cible : l'expéditeur peut continuer à exécuter d'autres parties de son code logique. Ce mécanisme de messagerie asynchrone, comparé aux appels synchrones d'Ethereum, offre une plus grande flexibilité et extensibilité, réduit les goulets d'étranglement dus à l'attente de réponse, mais introduit également des défis liés à la gestion de la concurrence et des conditions de course.
Format et structure des messages
Sur TON, un message contient généralement l'expéditeur, le destinataire, le montant transféré et le corps du message. Ce dernier peut contenir un appel de fonction, des données ou tout autre contenu personnalisé. Le format de message utilisé par TON permet une définition et une extension flexibles, facilitant ainsi un échange efficace d'informations variées entre différents contrats.
cell msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(addr)
.store_coins(amount)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_slice(message_body)
.end_cell();
File d'attente des messages et traitement des états
Chaque contrat maintient une file d'attente de messages, stockant ceux qui n'ont pas encore été traités. Pendant l'exécution, le contrat traite les messages un par un selon leur ordre dans la file. Comme le traitement est asynchrone, l'état du contrat n'est pas mis à jour immédiatement après réception d'un message.
Avantages du mécanisme de messagerie asynchrone
-
Mécanisme de sharding efficace : Le modèle asynchrone de TON s'intègre parfaitement à sa conception en shards. Chaque shard traite indépendamment les messages et les modifications d'état des contrats, évitant ainsi les retards causés par les communications synchrones inter-shards. Cette architecture améliore considérablement le débit global et l'extensibilité du réseau.
-
Réduction de la consommation de ressources : Puisque les messages asynchrones n'exigent pas de réponse immédiate, l'exécution d'un contrat sur TON peut s'étaler sur plusieurs blocs, évitant une surconsommation de ressources dans un seul bloc. Cela permet à TON de supporter des contrats intelligents plus complexes et gourmands en ressources.
-
Robustesse et fiabilité : Le mécanisme de messagerie asynchrone rend le système plus tolérant aux pannes. Par exemple, si un contrat ne peut pas répondre immédiatement en raison de limitations de ressources ou d'autres causes, l'expéditeur peut continuer à exécuter d'autres opérations, sans que le système entier ne soit bloqué par le retard d'un seul contrat.
Défis liés à la conception de contrats asynchrones
-
Problèmes de cohérence d'état : En raison de la nature asynchrone des messages, l'état d'un contrat peut recevoir des messages différents à des moments distincts. Les développeurs doivent donc prêter une attention particulière à la cohérence d'état. Lors de la conception d'un contrat, il faut anticiper les changements d'état pouvant résulter de différents ordres de messages, afin de garantir que le système reste cohérent dans toutes les situations.
-
Conditions de course et mesures de protection : Le traitement asynchrone des messages expose à des risques de conditions de course, où plusieurs messages tentent simultanément de modifier l'état du contrat. Les développeurs doivent implémenter des mécanismes de verrouillage appropriés ou utiliser des opérations transactionnelles pour éviter les conflits d'état.
-
Considérations de sécurité : Dans les communications inter-contrats, les contrats asynchrones sont particulièrement vulnérables aux attaques de type « homme du milieu » ou aux attaques par rejeu. Il est donc essentiel, lors de la conception, d'anticiper ces risques et de mettre en œuvre des protections telles que l'utilisation d'horodatages, de nombres aléatoires (nonces) ou de signatures multiples.
Modèle de grand livre
Ton (The Open Network), lors de la conception de son infrastructure blockchain, adopte un modèle de compte abstrait et de grand livre particulier. Cette flexibilité se manifeste notamment dans la manière dont sont gérés l'état des comptes, la transmission des messages et l'exécution des contrats.
Abstraction des comptes
Le modèle de compte de Ton repose sur une abstraction basée sur les contrats : chaque compte peut être vu comme un contrat. Ce modèle présente des similitudes avec celui d’Ethereum, mais il est plus souple et généralisé. Sur Ton, un compte n’est pas seulement un conteneur d’actifs ; il contient également du code de contrat et des données d’état. Chaque compte est composé de son code (Code), de ses données (Data) et de sa logique de traitement des messages (Message Handling).
Structure du compte : Chaque compte Ton possède une adresse unique, générée à partir du hachage du code du compte, des données initiales au déploiement et d’autres paramètres. Cela signifie qu’un même code et les mêmes données initiales peuvent produire des adresses différentes selon l’environnement de déploiement (par exemple, sur une autre blockchain ou shard).
Flexibilité : Puisque chaque compte peut exécuter son propre code de contrat, les comptes Ton peuvent implémenter une logique très complexe. Ils ne se limitent pas à détenir un solde simple, mais peuvent gérer des transferts d’état complexes, des communications entre comptes ou encore des opérations automatisées selon des conditions spécifiques. Ce modèle rend donc les comptes Ton bien plus extensibles et flexibles que ceux des blockchains traditionnelles.
Structure du grand livre
La structure du grand livre de Ton est conçue pour traiter efficacement un grand volume de transactions concurrentes, tout en supportant la messagerie asynchrone et les opérations multi-shards. L’état de chaque compte est stocké dans une structure d’arbre de Merkle, ce qui confère au grand livre de Ton une capacité élevée de vérification d’état.
Stockage d’état
Les informations d’état des comptes sont conservées dans un stockage persistant organisé sous forme d’arbre de Merkle, assurant intégrité et sécurité. Cette conception permet également une interrogation et une vérification efficaces de l’état, notamment dans les scénarios de transactions inter-shards.
L’état d’un compte ou d’un contrat intelligent inclut généralement les éléments suivants :
-
Solde en monnaie de base
-
Soldes en autres monnaies
-
Code du contrat intelligent (ou son hachage)
-
Données persistantes du contrat intelligent (ou leur hachage Merkle)
-
Statistiques sur le nombre d’unités de stockage persistant et le nombre d’octets bruts utilisés
-
Date du dernier paiement effectué pour le stockage persistant du contrat (en réalité, le numéro de bloc de la chaîne principale)
-
Clé publique requise pour transférer des fonds et envoyer des messages depuis ce compte (optionnelle ; par défaut égale à account_id lui-même). Dans certains cas, un code de vérification de signature plus complexe, semblable à celui des sorties de transaction Bitcoin, peut être présent ici ; dans ce cas, account_id correspondra au hachage de ce code.
Toutes ces informations ne sont pas obligatoirement présentes dans chaque compte. Par exemple, le code du contrat intelligent concerne uniquement les contrats intelligents, pas les comptes « simples ». De plus, bien qu’un compte doive avoir un solde non nul en monnaie principale (par exemple, les Grams sur la chaîne principale ou les shards de la chaîne de travail de base), les soldes en autres monnaies peuvent être nuls. Afin d’éviter de conserver des données inutilisées, un type produit-somme est défini lors de la création de la chaîne de travail, utilisant différents octets marqueurs pour distinguer les différents « constructeurs ». Finalement, l’état du compte est stocké sous forme d’un ensemble de cellules dans le stockage persistant TVM.
Transmission et traitement des messages
La structure du grand livre de Ton intègre nativement le support de la messagerie asynchrone : chaque compte peut traiter indépendamment les messages reçus et mettre à jour son état. Ce mécanisme asynchrone permet des interactions complexes entre comptes, sans qu’un retard d’opération n’affecte le fonctionnement normal des autres comptes.
Modèle Gas
La blockchain Ton (The Open Network) optimise fortement l'efficacité d'exécution des contrats intelligents grâce à son modèle Gas unique. Le modèle Gas est utilisé dans les blockchains pour mesurer et limiter les ressources consommées pendant l'exécution d'un contrat intelligent. Comparé au modèle Gas des blockchains traditionnelles (comme Ethereum), le modèle de Ton est plus complexe et plus efficace, permettant une gestion plus précise de la consommation de ressources durant l'exécution des contrats.
Mesure fine de la consommation de Gas
Le modèle Gas de Ton mesure avec précision les ressources informatiques consommées, les opérations de stockage et les coûts de transmission de messages pendant l'exécution d'un contrat intelligent. En mesurant finement les ressources de calcul, de stockage et de messagerie, le modèle Gas de Ton empêche les opérations excessivement complexes de monopoliser trop de ressources. En limitant la consommation de Gas, Ton assure une répartition équitable des ressources informatiques entre tous les nœuds du réseau, évitant ainsi qu'un contrat ou une opération unique ne surcharge les ressources du réseau.
Traitement parallèle et optimisation du Gas
Ton prend en charge le traitement parallèle des contrats intelligents, permettant à plusieurs contrats de s'exécuter simultanément sur différents shards sans se bloquer mutuellement. Dans cette architecture, le modèle Gas est étroitement intégré aux mécanismes d'exécution parallèle et de sharding. En répartissant l'exécution des contrats sur plusieurs shards, Ton peut distribuer le calcul et le paiement du Gas sur différents nœuds et chaînes, évitant ainsi la congestion du réseau tout en maximisant l'utilisation des ressources.
Mécanisme dynamique d'ajustement du Gas
Le modèle Gas de Ton inclut un mécanisme d'ajustement dynamique, permettant de modifier les frais de Gas en fonction de la charge réelle du réseau. Cela signifie qu'en période de faible charge, les utilisateurs peuvent exécuter leurs contrats à moindre coût en Gas, encourageant ainsi les opérations durant ces périodes et équilibrant l'utilisation des ressources. Ce mécanisme améliore non seulement l'expérience utilisateur, mais régule aussi par voie de marché les pics de consommation de ressources.
Vulnérabilités fréquemment ignorées dans les contrats intelligents Ton
Dans notre précédent article d'analyse de la sécurité sur TON, nous avons déjà présenté en détail les vulnérabilités courantes dans l'écosystème Ton. Vous pouvez vous y référer via le tableau ci-dessous :


Cet article met l'accent sur les points de vulnérabilité dans les contrats TON que notre équipe a identifiés comme étant souvent négligés :
(1) Amélioration de la lisibilité du code
Dans les contrats intelligents TON, des valeurs numériques sont souvent utilisées pour stocker les données liées à l'envoi de messages. Par exemple, dans le code ci-dessous, plusieurs nombres sont utilisés pour représenter des identifiants ou longueurs de stockage, ce qui nuit gravement à la lisibilité et à la maintenabilité du code. D'autres développeurs ont du mal à comprendre la signification et l'utilité de ces nombres. Pour améliorer la lisibilité et la maintenabilité, il est recommandé de définir les valeurs numériques clés comme constantes nommées. Par exemple, remplacer 0x18 par NON_BOUNCEABLE.
check_std_addr(address);var msg = begin_cell() store_uint(0x18, 6) ;; nobounce store_slice(address) store_coins(amount) store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) end_cell();send_raw_message(msg, 1);
De même, concernant les messages d'erreur dans les conditions de validation du contrat, il est conseillé de remplacer les codes d'erreur par des variables explicites.
throw_unless(705, equal_slices(owner_address, sender_address));
(2) Utiliser end_parse() pour garantir l'intégrité des données
Dans les contrats TON, l'analyse des données suit un ordre fixe : les données de type spécifique sont chargées progressivement à partir des données brutes. Ce mode d'analyse garantit la cohérence et l'exactitude des données. Exemple ci-dessous :
() load_data() impure {
slice ds = get_data().begin_parse();
storage::owner = ds~load_msg_addr();
storage::amount = ds~load_uint(256);
storage::data = ds~load_ref();
storage::api_data = ds~load_ref();
ds.end_parse();
}
Notez que end_parse() sert à vérifier si la tranche de données (slice) est vide. Si elle ne l'est pas, une exception est levée. Cela garantit que le format et le contenu des données sont conformes aux attentes. Si end_parse() détecte que des données restent dans la tranche, cela peut indiquer que l'analyse n'a pas été complètement effectuée ou que le format des données est incorrect. Appeler end_parse() permet donc de détecter toute omission ou anomalie lors de l'analyse.
(3) Erreurs dues à la non-concordance entre types de stockage et de lecture
Il convient ici de souligner la compatibilité entre les types int et uint lors du stockage et du chargement. Dans l'exemple ci-dessous, la valeur int -42 est stockée avec store_int(), mais est ensuite récupérée avec load_uint(), ce qui peut provoquer une erreur.
() Test_Function() {
var cell = begin_cell();
cell = cell.store_int(-42, 32);
var my_cell = cell.end_cell();
slice s = my_cell.begin_parse();
var result = s.load_uint(32);
}
(4) Utilisation appropriée des modificateurs inline_ref et inline
Premièrement, clarifions la différence entre inline_ref et inline :
inline : Une fonction marquée inline voit son code inséré directement à chaque point d'appel. À chaque invocation, le code réel de la fonction est copié à l'emplacement d'appel, au lieu d'une redirection vers le corps de la fonction comme pour une fonction normale.
inline_ref : Une fonction marquée inline_ref a son code stocké dans une cellule indépendante. À chaque appel, la machine virtuelle TON exécute ce code via la commande CALLREF, sans l'insérer à l'emplacement d'appel.
Ainsi, le modificateur inline convient aux fonctions simples, réduisant la surcharge d'appel, mais peut entraîner une duplication du code du contrat. En revanche, inline_ref convient mieux aux fonctions complexes ou fréquemment appelées, car il stocke le code dans une cellule séparée, améliorant l'efficacité et évitant la duplication. En résumé : pour les fonctions volumineuses ou appelées de multiples fois, privilégiez inline_ref ; sinon, utilisez inline.
(5) Identifier correctement la chaîne de travail
TON autorise la création de jusqu'à 2^32 chaînes de travail, chacune pouvant être divisée en 2^60 shards. Actuellement, seules deux chaînes existent : la chaîne principale (-1) et la chaîne de base (0). Lors du calcul de l'adresse cible dans un contrat, il est essentiel de spécifier explicitement l'ID de la chaîne concernée afin de garantir que l'adresse du portefeuille générée appartienne à la bonne chaîne de travail. Pour éviter les erreurs d'adressage, il est recommandé d'utiliser force_chain() pour imposer l'ID de chaîne.
(6) Éviter les conflits de codes d'erreur
Dans la conception de contrats, la gestion des codes d'erreur est cruciale pour garantir la conformité et éviter toute confusion. Pour les contrats intelligents TON, il faut d'abord s'assurer que chaque code d'erreur est unique au sein du contrat, évitant ainsi les doublons qui pourraient entraîner ambiguïté. Ensuite, il convient d'éviter les conflits avec les codes d'erreur standards définis par la plateforme ou le système sous-jacent — par exemple, le code 333 indique une incompatibilité d'ID de chaîne. Il est donc conseillé de choisir les codes d'erreur du contrat entre 400 et 1000.
(7) Stocker les données et appeler return() après une opération
Dans un contrat intelligent TON, le traitement des messages sélectionne différentes logiques selon l'op-code. Après l'exécution de la logique métier, deux actions sont requises : premièrement, si des données sont modifiées, save_data() doit être appelé pour enregistrer ces modifications, faute de quoi elles seront perdues ; deuxièmement, return() doit être appelé pour indiquer la fin de l'opération, sinon une exception throw(0xffff) sera levée.
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
int flags = cs~load_uint(4);
if (flags & 1) {
;; ignore all bounced messages
return ();
}
slice sender_address = cs~load_msg_addr();
load_data();
int op = in_msg_body~load_op();
if ((op == op::op_1())) {
handle_op1();
save_data();
return ();
}
if ((op == op::op_2())) {
handle_op2();
save_data();
return ();
}
if ((op == op::op_3())) {
handle_op3();
save_data();
return ();
}
throw(0xffff);
}
En conclusion, la blockchain TON, grâce à son architecture innovante et son environnement de développement flexible, devient progressivement une plateforme idéale pour les développeurs d'applications décentralisées. Toutefois, à mesure que les contrats intelligents jouent un rôle croissant dans l'écosystème TON, la sécurité des contrats ne doit pas être négligée. Les développeurs doivent approfondir leur compréhension des particularités de l'écosystème TON, suivre strictement les meilleures pratiques, renforcer les audits de sécurité et garantir la solidité et la sûreté des contrats. Seulement ainsi, pourront-ils tirer pleinement parti des avantages de la plateforme TON, construire des applications décentralisées plus sûres et fiables, et contribuer activement au développement sain de l'écosystème.
L'écosystème TON connaît actuellement une croissance rapide, attirant de nombreux capitaux et utilisateurs actifs. Cependant, les problèmes de sécurité qui en découlent ne doivent pas être sous-estimés.
Bienvenue dans la communauté officielle TechFlow
Groupe Telegram :https://t.me/TechFlowDaily
Compte Twitter officiel :https://x.com/TechFlowPost
Compte Twitter anglais :https://x.com/BlockFlow_News














