Tact智能合约安全实践:TON生态系统中的常见错误

TON(The Open Network)以其创新特性和强大的智能合约性能,不断拓宽区块链技术的边界。基于早期的区块链平台(如以太坊等)的经验与教训,TON为开发者提供了一个更加高效且灵活的开发环境。其中推动这一进步的关键要素之一便是Tact编程语言。

Tact是专为TON链设计的一种全新编程语言,以高效与简洁为核心目标。它易于学习和使用,并与智能合约完美契合。Tact是一种静态类型语言,拥有简单的语法和强大的类型系统。

尽管如此,开发者在使用FunC时遇到的许多问题,在Tact开发中仍然存在。以下将结合审计实践案例,分析Tact开发中的一些常见错误。

数据结构

  可选地址

Tact语言简化了声明、解码和编码的数据结构。然而,开发者仍需保持谨慎。我们来看一个例子:

这是根据TEP-74标准用于转移jetton的内部传输(InternalTransfer)消息声明。请注意response_destination的声明,它是一个地址(Address)类型。在Tact中,要求地址必须是非零地址。然而,jetton标准的参考实现允许零地址(addr_none),它由两个零位表示。这意味着用户或其他合约可能会尝试发送带有零响应地址的jetton,而该操作会意外失败。

此外,如果用户发送给其钱包的Transfer消息允许设置response_destination,而从发送方钱包到接收方钱包的InternalTransfer消息却不支持该参数,那么jetton将会“飞出”,意味着jetton无法到达目标地址,最终导致丢失。稍后,我们将讨论一种例外情况,即如何正确处理被退回的消息。息会被妥善处理。

在这种情况下,允许零地址的更好结构声明应为Address?,但在Tact中,将可选地址传递到下一条消息目前较为繁琐。

  数据序列化

在Tact中,开发者可以指定字段的序列化方式。

本例中,totalAmount将序列化为coins,而releasedAmount将序列化为int257(默认为Int)。releasedAmount可以是负值,并且将占用257位。在大多数情况下,省略序列化类型不会带来问题;然而,如果数据涉及到通信,这就变得至关重要。

以下是我们审计的项目中的一个例子:

该数据结构是由NFT项目用作对链上get_static_data请求的回复。根据标准,回复应该是:

上述索引是uint256(而不是int257),这意味着返回的数据将被调用者错误解读,从而导致不可预测的结果。很可能的结果是report_static_data处理程序会发生回滚,消息流也会因此中断。这些例子说明了为什么即使在使用Tact时,考虑数据序列化也是至关重要的。

  有符号整数

不指定Int的序列化类型可能会导致比上述示例更严重的后果。与coins不同,int257可以为负值,这常常会让程序员感到意外。例如,在Tact的实时合约中,看到amount: Int是极其常见的。

这种写法本身并不一定意味着存在漏洞,因为该金额(amount)通常会被编码到JettonTransfer消息中,或传递到send(SendParameters{value: amount}),后者使用的是coins类型,不允许负值。然而,在一个案例中,我们发现一个拥有大量余额的合约,它允许用户将所有值设置为负数,包括奖励、手续费、金额、价格等。因此,恶意行为者可能利用这一漏洞进行攻击。

并发

以太坊链的开发者必须注意重入攻击,即在当前函数执行完成之前,能够再次调用同一个合约的函数。而在TON链上,重入攻击是不可能的。

由于TON是一个支持异步和并行智能合约调用的系统,追踪处理动作的顺序可能变得更加困难。任何内部消息都会被目标账户接收,交易结果会在交易本身之后处理,但并没有其他保证(有关消息传递的更多信息请参见相关文档)。

我们无法预测消息3或消息4哪个会先被送达。

在这种情况下,中间人攻击(Man-in-the-Middle Attack)在消息流中是高发的攻击类型。为了确保安全,开发者应该设定每条消息的传递时间为1到100秒,在此期间,任何其他消息都有可能被传递。以下是一些可以提高安全性的其他注意事项:

1. 不要检查或更新合约状态以供消息流的后续步骤使用。

2. 使用携带值模式(carry-value pattern)。不要直接发送有关值的信息,而是与消息一起发送。

以下是一个存在漏洞的真实例子:

在上述示例中,发生了以下步骤:

1. 用户通过collection_jetton_wallet向NftCollection发送jetton。

2.TransferNotification被发送到NftCollection合约,合约记录了received_jetton_amount。

3. 合约将jetton转发给NftCollection的所有者。

4. 向NftCollection发送Excesses消息,作为response_destination。

5. NftItem在Excesses处理程序中部署,使用received_jetton_amount。

这里有几个问题需要注意:

首先,Excesses消息并不能保证按照jetton标准被送达。如果没有足够的gas费来发送Excesses消息,它将被跳过,消息流将停止。

其次,更新received_jetton_amount并在后续使用它会使系统容易受到并发执行的影响。其他用户可能会同时发送另一个金额并覆盖已保存的金额,这也可能会被恶意利用以从中获利。

在并发的情况下,TON与传统的中心化多线程系统相似。

  处理退回消息

许多合约忽视了退回消息的处理。然而,Tact使这一过程变得简单明了:

要决定消息是否应以可退回模式发送,可以考虑两个因素:

1. 如果消息失败,谁应该收到附加的Toncoin?如果目标应该接收这些资金,而不是发送合约,那么就以非可退回模式发送消息。

2. 如果下一个消息被拒绝,消息流会发生什么?如果通过处理退回的消息可以恢复一致的状态,那么最好进行处理。如果不能恢复,最好修改消息流。

以下是jetton标准中的一个例子:

1. Excesses消息以非可退回模式发送,因为合约不需要返回toncoins。

2. 以非可退回模式发送TransferNotification消息,因为forward_ton_amount属于调用者,合约不会保留它。

3. 相反,BurnNotification是以可退回模式发送,因为如果它被jetton主合约退回,钱包需要恢复其余额,以保持total_supply一致。

4. InternalTransfer也是可退回的。如果接收方拒绝资金,发送方的钱包必须更新余额。

请记住以下几点:

1. 退回消息仅接收256位的原始消息;在消息识别之后,有效数据仅有224位。因此,你将得到有限的关于失败操作的信息,通常是存储为coins的某个金额。

2. 如果没有足够的gas费,退回的消息将无法送达。

3. 退回消息本身无法再次被退回。

  返回Jetton

在某些情况下,撤销和处理退回消息不是一个选项。最常见的例子是当你的合约收到TransferNotification关于到达的jetton时,退回该消息可能会导致jetton永远被锁定。相反,你应该使用try-catch块来处理。

让我们来看一个例子。在EVM中,当一笔交易被撤销时,所有结果都会被回滚(除了gas——它会被矿工收取)。但在TVM中,“交易”被分解为一系列消息,因此只回滚其中一条消息很可能会导致“合约组”状态不一致。

为了解决这个问题,必须手动检查所有条件,并在紧急情况下来回发送修正消息。然而,由于在没有异常的情况下解析有效载荷非常繁琐,因此最好使用try-catch块。

下面是一个典型的Jetton接收代码示例:

请注意,如果gas费不足,即使是将jettons发送回去也无法正常工作。此外,需要注意的是,我们是通过sender()的“钱包”返还jetton,而不是通过我们合约的实际jetton钱包返还。这是因为任何人都可以手动发送TransferNotification消息来欺骗我们。

  管理Gas费

在审计TON合约时,最常见的问题之一就是gas费管理问题。主要原因有两个:

1. 缺乏gas费控制可能导致以下问题

消息流执行不完整:部分操作会生效,而另一部分由于gas不足而被回滚。例如,如果奖励获取操作在jetton钱包中完成,但销毁份额操作在jetton主合约中被忽略,那么整个合约组将变得不一致。

用户可以提取自己的合约余额:此外合约中可能会积累过多的Toncoin。

2. TON合约开发者难以管理和控制gas:Tact的开发者需要通过测试来获得gas消耗量,并在开发过程中每次更新消息流时都更新相应的数值。

我们建议的做法如下:

1. 确定“入口点”:这些是所有可以接受来自“外部”消息的消息处理器,即来自终端用户或其他合约(如Jetton钱包)。

2. 对于每个入口点,绘制所有可能的路径并计算gas消耗。使用printTransactionFees()(可在@ton/sandbox中找到,该工具随Blueprint一起提供)。

3. 如果可以在消息流过程中部署合约,则假设它将被部署。部署将消耗更多的gas费和存储费用。

4. 在每个入口点,根据情况添加最低的gas要求。

5. 如果处理器不发送更多消息(消息流在此终止),那么最好返回Excesses,如下所示:

不发送Excesses也是可以的,但对于像Jetton Master这样的高吞吐量合约,存在大量BurnNotification消息或大量传入转账的合约,累计金额可能会迅速增长。

6. 如果处理器只发送一条消息——包括emit(),实际上是一个外部消息——最简单的方式是通过forward()传递剩余的gas费(见上文)。

7. 如果处理器发送多条消息,或者如果通讯中涉及ton数量,那么计算应发送金额比计算应剩余金额要更容易。

在下一个例子中,假设合约希望将forwardAmount发送给两个子合约作为押金:

正如你所看到的,gas费管理需要高度关注,即使是在简单的情况下。请注意,如果你已经发送了消息,则不能在send()模式中使用SendRemainingValue标志,除非你故意想要从合约余额中支出资金。

结论

随着TON生态系统的发展,Tact智能合约的安全开发将变得越来越重要。虽然Tact提供了更高的效率和简洁性,但开发者必须保持警惕,避免常见的陷阱。通过了解常见错误并实施最佳实践,开发者可以充分开发Tact的潜力,创建强大而安全的智能合约。持续学习并遵循安全实践指南,将确保TON生态的创新能力得到安全有效地利用,从而为更安全、可信的区块链环境作出贡献。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/939262.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C进阶—指针(1)

若是阁下满意的话,可否一键三连呢! 第一篇进阶指针就是先了解各种新的概念(用法我们后面几篇再详细说!先只介绍概念),有疑惑很正常,只是暂时的,我们一起来看看吧! 字符指…

【Python使用】嘿马头条项目从到完整开发教程第9篇:缓存,1 缓存穿透【附代码文档】

本教程的知识点为:简介 1. 内容 2. 目标 产品效果 ToutiaoWeb虚拟机使用说明 数据库 理解ORM 作用 思考: 使用ORM的方式选择 数据库 SQLAlchemy操作 1 新增 2 查询 all() 数据库 分布式ID 1 方案选择 2 头条 使用雪花算法 (代码 toutiao-backend/common/…

谷歌浏览器的扩展程序自动更新设置

谷歌浏览器是全球最受欢迎的网络浏览器之一,其扩展程序更是为用户提供了丰富的功能。然而,随着时间的推移,扩展程序需要更新以修复漏洞、提升性能或增加新功能。本文将详细介绍如何在Chrome中设置扩展程序的自动更新。(本文由http…

LabVIEW与PLC点位控制及OPC通讯

在工业自动化中,PLC通过标准协议(如Modbus、Ethernet/IP等)与OPC Server进行数据交换,LabVIEW作为上位机通过OPC客户端读取PLC的数据并进行监控、控制与处理。通过这种方式,LabVIEW能够实现与PLC的实时通信&#xff0c…

在Windows Server路由和远程访问服务中启用L2TP/IPsec VPN

背景 路由和远程访问服务(Routing and Remote Access Services,RRAS)是Windows Server上的一个角色,包含很多功能,可以用来搭建VPN。然而,在什么也不做的初始配置中,它只允许PPTP协议连接。然而…

Android简洁缩放Matrix实现图像马赛克,Kotlin

Android简洁缩放Matrix实现图像马赛克,Kotlin 原理,通过Matrix把一个原图缩小到原先的1/n,然后再把缩小后的小图放大n倍,自然就是马赛克效果(相当于是放大后像素“糊”成一片了)。 import android.content.…

《Posterior Collapse and Latent Variable Non-identifiability》

看起来像一篇很有用的paper,而且还是23年的 没看完 后边看不懂了 Abstract 现有的解释通常将后验崩塌归因于由于变分近似而使用神经网络或优化问题。 而本文认为后验崩塌是潜在变量不可识别性的问题(a problem of latent variable non-identifiability) 本文证明了…

网络视频监控平台/安防监控/视频综合管理Liveweb视频汇聚平台解决方案

一、当前现状分析 当前视频资源面临以下问题: 1)不同单位在视频平台建设中以所属领域为单位,设备品牌众多,存在的标准不一,各系统之间也没有统一标准; 2)各单位视频平台建设分散、统筹性差&am…

【前端爬虫】关于如何获取自己的请求头信息(user-agent和cookie)

注意:由于user-agent和cookie中保存了部分账户信息,所以一定不要随意泄露给他人!!! 1.首先打开某个页面,点击键盘的F12键进入控制台,或者鼠标右键页面选择打开控制台 2.然后点击控制台上方的网…

共创共建!葡萄城 SpreadJS 完成 HarmonyOS NEXT 操作系统兼容认证

最新技术资源(建议收藏) https://www.grapecity.com.cn/resources/ 近日,华为“企业工作必备应用鸿蒙化论坛”在北京圆满落幕,论坛汇聚了众多行业精英和合作伙伴,聚焦讨论企业数字化转型与原生鸿蒙生态融合等话题。葡萄…

单项链表的学习

1:链表概念 链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 1:结点 与顺序表不同的是,链表⾥的每节"⻋厢"都是独⽴申请下来的空间,我们称之为“结点 / 结…

基于大语言模型的多代理下一代制造系统能灵活动态管理制造资源的高效调度方法

摘要 论文地址:https://arxiv.org/pdf/2405.16887 随着生产率的提高,客户对多品种、小批量生产的需求也在不断增加,这反过来又对制造系统提出了更高的要求。由于这种需求,当生产任务频繁变化时,传统的制造系统往往无法…

FPGA-PS端编程1:

目标 在小梅哥的zynq 7015上,完成以下目标: 读取 S1 按键的电平, 当 S1 按键为按下状态时,驱动 PS LED 以 1S 的频率闪烁(注意理解 1S 的频率闪烁和 1S的时间翻转两种描述之间的差别), 当 S1 释放后,停止…

模型 QFD(质量功能展开/质量屋)

系列文章 分享 模型,了解更多👉 模型_思维模型目录。将客户需求转化为产品设计。 1 模型 QFD(质量功能展开)的应用 1.1 电信服务及网络维护过程质量改进QFD应用案例 背景介绍: 随着中国加入WTO和国家对电信管制的普遍…

安装@wangeditor/editor-for-vue失败原因

链接: 安装wangeditor/editor-for-vue失败原因 或者下述命令行: 安装成功可到packa.json里面查看:

敏捷多模态微型机器人:独特的被动变形轮设计

大家好!今天来了解一种微型机器人——《An agile multimodal microrobot with architected passively morphing wheels》发表于《SCIENCE ADVANCES》。这个微型机器人,具有独特的设计和卓越的性能。它带有被动变形轮子,这种轮子的设计灵感源自…

键盘扫描及显示设计实验-微机原理与接口技术课程设计

1.实验要求 将 8255 单元与键盘及数码管显示单元连接,编写实验程序,扫描键盘输入,并将扫描结果送数码管显示。键盘采用 44 键盘,每个数码管显示值可为 0~F 共 16 个数。实验具体内容如下:将键盘进行编号&am…

超维机器人油气化工智能巡检解决方案

随着油气化工行业的快速发展和生产环境的日益复杂,安全、环保和高效的运营管理成为企业发展的关键目标。然而,传统的人工巡检方式面临着许多挑战,包括安全隐患、效率低下和人为误差等问题。为了应对这些挑战,智能化技术的引入为油…

unity webgl部署到iis报错

Unable to parse Build/WebGLOut.framework.js.unityweb! The file is corrupt, or compression was misconfigured? (check Content-Encoding HTTP Response Header on web server) iis报错的 .unityweb application/octet-stream iis中添加 MIME类型 .data applicatio…

【Lua热更新】下篇 -- 更新中

上篇链接:【Lua热更新】上篇 文章目录 三、xLua热更新📖1.概述📚︎2.导入xLua框架🔖3. C#调用Lua3.1Lua解析器3.2Lua文件夹的重定向3.3Lua解析器管理器3.4全局变量获取3.5全局函数获取3.6映射到List和Dictionary3.7映射到类3.8映…