Web3.0安全开发实践:Clarity最佳实践总结

在过去的一段时间里,CertiK团队对比特币生态系统及其发展进行了深入研究。同时,团队还审计了多个比特币项目以及基于不同编程语言的智能合约,包括OKX的BRC-20钱包和MVC DAO的sCrypt智能合约实现。

现在,我们的研究重点转向了Clarity。CertiK团队在圆满完成多个Clarity漏洞赏金项目后,获得了更多关于其安全问题和常见实践的洞见。本文将分享这些见解以及经验,以期可以帮助到生态建设者。

Clarity是一种由Hiro PBC、Algorand和其他利益相关者共同开发的智能合约语言。目前,它已在Stacks链(比特币侧链)上得到应用。Clarity的主要目标是提供高度的可预测性和安全性,确保智能合约按预期执行,不会产生任何出乎意料的副作用。

接下来,我们将探讨Clarity智能合约背后的概念,以及使用Clarity编程的最佳实践和安全检查清单。

Clarity语言

Clarity的设计源自对智能合约工程中漏洞的深入分析,特别是对Solidity中观察到的漏洞的研究。它的关键特性包括以下几点:

  • 可解释语言:确保所见即所得。

  • 可判定属性:保证可预测结果和有限执行。

  • 安全措施:防范重入攻击、溢出和下溢,这些对保持合约完整性至关重要。

  • 自定义代币支持:简化开发流程,便于创建和管理代币。

  • 事务后置条件:通过验证执行后的状态变化来增强安全性。

Clarity的独特之处在于它从LISP语言中汲取灵感,LISP以其处理符号信息的简洁性和强大功能而闻名。在Clarity中,一切都以“列表中的列表”或“表达式中的表达式”的形式表示。这种嵌套结构是Clarity的核心特点,使其语言具有高度的表达性和灵活性。函数定义、变量声明和函数参数都被封装在括号内,强调了语言的语法统一性。

以下是定义一个简单Clarity函数的示例:

(define-data-var count int 0) //State Variable Declaration(define-public (increase-number (number int)) //Function definition   (let       (           (current-count count)       )       (var-set count (+ 1 number))       (ok (var-get count))   ))(increase-number 1) //Function call

通过理解和利用这些嵌套表达式,开发者可以创建符合Stacks区块链功能要求的安全高效的智能合约。这种方法不仅增强了可读性,还确保合约的确定性和可预测性——这是保持去中心化应用安全性和可信度的关键。

Clarity与Solidity的区别

1. 解释型与编译型

  • Clarity:Clarity是一种解释型语言,意味着源代码直接发送到Stacks区块链并在区块链上执行,而无须编译成字节码。

  • Solidity:Solidity代码首先需要编译成字节码,然后将字节码部署到区块链上。EVM(以太坊虚拟机)会验证这些字节码,并调度相应的操作码进行执行。

2. 无动态调度

  • Clarity不支持动态调度,并且不是图灵完备的,这意味着要执行的函数是预先确定的。这个特性简化了执行模型,并有助于防止重入攻击,使Clarity本身更加安全。

Clarity智能合约安全

安全一直是DeFi领域的头等大事,尤其是在Stacks网络扮演关键角色的比特币DeFi生态系统中。截至2024年8月,Stacks生态系统中的总锁仓价值(TVL)已达到约为8000万美元,因此强大的安全措施变得尤为重要。

截至目前,Stacks已经发生了多起安全事件,导致超过200万美元的损失。这些事件突显了对Clarity智能合约进行安全审计的必要性。

安全事件案例

2024年4月11日,Stacks网络上的借贷协议Zest Protocol(比特币L2)遭遇了一次重大漏洞攻击,攻击目标是协议的借款池(Borrow Pool),导致损失约322,000STX(折约100万美元)。这次黑客攻击事件迄今为止是比特币DeFi生态系统中损失最严重的事件。

Zest Protocol的借款功能在合约pool-borrow.clar中定义,允许用户通过提供抵押物来借入资产。该功能的参数包括池储备、价格预言机、借入的资产、流动性提供者代币、抵押资产列表、借款金额、费用计算器、利率模式和所有者:

(define-public (borrow (pool-reserve principal) (oracle <oracle-trait>) (asset-to-borrow <ft>) (lp <ft>) (assets (list 100 { asset: <ft>, lp-token: <ft>, oracle: <oracle-trait> })) (amount-to-be-borrowed uint) (fee-calculator principal) (interest-rate-mode uint) (owner principal))

pool-borrow-v1-1.clar 中的借款函数

攻击者利用了assets(资产)参数,该参数是一个最多包含100种资产的列表,用作抵押物。其漏洞源于合约未能成功验证抵押资产的唯一性。更具体地说,合约在验证资产存在性时未检查重复项。这个疏忽使攻击者能够通过多次列出同一资产操纵抵押物的价值。

其他协议也遭遇过类似的安全漏洞攻击。例如,2021年10月,一名攻击者从Arkadiko Swap中窃取了约400,000枚STX和740,000枚USDA(总计约150万美元)。攻击者利用了Arkadiko Swap智能合约代码中的一个漏洞,该漏洞未能在创建新的交易对时正确验证LP代币。该漏洞使攻击者能够零成本铸造大量LP代币,随后从STX/USDA池中提取底层资产,影响了该池总价值的25%的资产。

Clarity智能合约的最佳实践与检查清单

我们总结了广泛研究后取得的经验,并为Clarity智能合约开发者编制了最佳实践和检查清单。以下是关键点:

1. 避免使用-panic函数

在Clarity智能合约中解包值时,避免使用unwrap-panic和unwrap-err-panic等函数。当这些函数解包失败时,它们会以运行时错误中止调用,却也没有为与合约交互的应用程序提供有意义的信息。但如果选择使用unwrap!和unwrap-err!,并附加明确的错误代码。这个方法不仅能够提高了错误的处理能力,还便于调试,并增强了智能合约的韧性。使用具体的错误代码可以使调用应用程序更高效地处理错误,并根据上下文采取适当的措施。

2. 避免使用tx-sender进行验证

在Clarity智能合约中滥用tx-sender变量进行身份验证可能导致安全漏洞,类似于Solidity中SWC-115列出的漏洞。tx-sender变量标识调用链的发起者,类似于Solidity中的tx.origin。使用tx-sender进行验证可能会引发网络钓鱼攻击,攻击者可以欺骗用户并在易受攻击的合约上执行经过身份验证的操作。

tx-sender与contract-caller的对比

另一方面,contract-caller表示当前调用的发送者。通过避免使用tx-sender进行身份验证,并采用更安全的替代方案如contract-caller,开发者可以降低网络钓鱼攻击和跨站脚本攻击的风险。

3. 模块化合约设计以增强灵活性和未来可升级性

一旦智能合约部署到区块链上,它就变得不可修改。与传统应用开发相比,这种不可变性带来了挑战,这意味着它不可以随时进行更新和修复。在智能合约开发中,确保灵活性和未来可升级性需要采取战略方法,因为一旦合约部署,就没有直接的方法可以更新合约代码。

解决这些挑战,开发者应考虑以下原则:

保持逻辑分离:避免创建一个处理所有功能的单一合约。而应该,通过将智能合约模块化,将其拆分为更小、独立的并且可以相互交互的组件。这种方法不仅使合约更易于管理和理解,还能在不影响整个系统的情况下替换或升级单个组件。

无状态合约:该合约可以在区块链上存储最少量的数据,从而减少了未来更改的复杂性和潜在影响。通过将状态保留在合约外部并作为输入参数传递,您可以更新逻辑而无须修改合约的状态。

避免硬编码变量:将值直接硬编码到合约代码中可能导致其缺乏灵活性,且妨碍未来的更新。相反,若将关键变量定义为可配置的参数,这些参数则可以通过合约函数进行设置或调整。

4. 避免基于区块高度(block-hight)的时间计算

在Clarity智能合约中,避免依赖block-height关键字进行时间敏感的计算。Stacks链的区块时间可能会随着网络升级而变化,例如Nakamoto版本的发布将会减少区块时间。而应该使用burn-block-height关键字,它反映了底层比特币区块链的当前区块高度。比特币的区块时间更稳定,不太可能发生变化,从而确保合约操作的更高准确性和可靠性。这种做法有助于保持一致性,并防止由于Stacks区块时间波动而引发的潜在问题。

5. 正确处理函数中的返回值

在开发Clarity智能合约时,必须正确处理函数的布尔返回值,尤其是处理像verify-mined()等函数时。

该函数返回三种可能的值:(ok true)、(ok false)或错误。如果返回(ok true),表示交易已在指定区块成功挖掘。如果返回(ok false),则表示交易未被挖掘,而错误则表示Merkle证明存在问题。

在使用try!检查ok/error,但未能验证响应类型中封装的布尔值时,会出现一个常见问题。这种疏忽可能导致即使交易未在区块中被挖掘(即返回值为(ok false)),函数也不会失败。结果是验证者可能会合作签署一个未被挖掘的交易,使其未经检查就通过索引器。这一漏洞使得未经验证的未挖掘和潜在恶意的交易得以处理,从而导致安全漏洞和系统内未经授权的操作。

为了降低这种风险,请确保您的代码检查错误并明确验证函数返回的布尔值。这种做法有助于维护合约的完整性和安全性,确保只处理有效的挖矿交易。

6. 在Clarity中正确使用contract-call?

在开发Clarity智能合约时,必须使用contract-call?函数正确实现合约间调用。该函数从被调用的智能合约返回一个Response(响应)类型的结果。

contract-call?的两种类型:

  • 静态调用(Static Call):被调用的是一个已知的不变合约,在调用者合约部署时可在链上使用。第一个参数是被调用者的本金,然后是方法名称及其参数。

(contract-call?    .registrar    register-name    name-to-register)

  • 动态调用(Dynamic Call):将被调用者作为参数传递,并将其类型化为特征引用(trait reference)。通过引用特征,代码可以更加灵活和可重用。

(define-public (swap (token-a <can-transfer-tokens>)                     (amount-a uint)                     (owner-a principal)                     (token-b <can-transfer-tokens>)                     (amount-b uint)                     (owner-b principal)))    (begin        (unwrap! (contract-call? token-a transfer-from? owner-a owner-b amount-a))        (unwrap! (contract-call? token-b transfer-from? owner-b owner-a amount-b))))

在处理合约调用时,请注意以下限制:

  • 在静态调用中,被调用者智能合约在创建时必须存在。

  • 智能合约的调用图中不得存在循环。这可以防止递归(和重入)。这种结构可以通过对调用图的静态分析检测出来,并将被网络拒绝。

  • contract-call?仅用于合约间调用。当调用者同时也是被调用者时,如果尝试执行,则会中止交易。

结语

CertiK已对Clarity智能合约安全进行了广泛地研究。作为一家在智能合约安全领域拥有丰富经验的Web3.0头部安全审计公司,CertiK已发现并报告了多个基于Clarity的漏洞赏金项目中的漏洞。如需了解我们之前的风险分析报告,可以访问我们的博客。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Chrome离线安装包下载

1、问Chrome的官网&#xff1a;https://www.google.cn/chrome/ 直接下载的是在线安装包&#xff0c;安装需要联网。 2、如果需要在无法联网的设备上安装Chrome&#xff0c;需要在上面的地址后面加上?standalone1。 Chrome离线安装包下载地址&#xff1a;https://www.google.c…

【从零开始的LeetCode-算法】3232. 判断是否可以赢得数字游戏

给你一个 正整数 数组 nums。 Alice 和 Bob 正在玩游戏。在游戏中&#xff0c;Alice 可以从 nums 中选择所有个位数 或 所有两位数&#xff0c;剩余的数字归 Bob 所有。如果 Alice 所选数字之和 严格大于 Bob 的数字之和&#xff0c;则 Alice 获胜。 如果 Alice 能赢得这场游…

前端速通(JavaScript)

1 初识JavaScript 1 JavaScript是什么 JavaScript 是一种高层的、轻量级的、解释型的编程语言&#xff0c;最初由 Netscape 公司于 1995 年开发。它的特点包括&#xff1a; 动态性&#xff1a;JavaScript是动态类型语言&#xff0c;允许开发者灵活地操作数据。跨平台&#xf…

分层架构 IM 系统之架构演进

在电商业务日活几百万的情况下&#xff0c;IM 系统采用分层架构方式&#xff0c;如下图。 分层架构的 IM 系统&#xff0c;整体上包含了【终端层】、【入口层】、【业务逻辑层】、【路由层】、【数据访问层】和【存储层】&#xff0c;我们在上篇文章&#xff08;分层架构 IM 系…

基于ToLua的C#和Lua内存共享方案保姆级教程

C#和Lua内存共享方案保姆级教程 前言 在介绍C#和Lua内存共享方案之前,先介绍下面两个点来支撑这个方案的必要性 跨语言交互很费 Lua和C#交互最早是基于反射的方式实现的,后来为了提升性能发展成Luajit+C#静态方法导出注入到lua虚拟机的方式至此Lua+Unity的性能才达到了实…

SpringSecurity创建一个简单的自定义表单的认证应用

1、SpringSecurity 自定义表单 在 Spring Security 中创建自定义表单认证应用是一个常见的需求&#xff0c;特别是在需要自定义登录页面、认证逻辑或添加额外的表单字段时。以下是一个详细的步骤指南&#xff0c;帮助你创建一个自定义表单认证应用。 2、基于 SpringSecurity 的…

创客匠人老蒋:个人IP如何获取有效流量?

大家好&#xff0c;我是老蒋。 为什么我反复强调说&#xff0c;如果你想把个人IP、创始人IP做起来&#xff0c;想把自己直播间的流量变大变活&#xff0c;一定要去参加这场将在2024年底举办的《全球创始人IP领袖高峰论坛》&#xff1f;一定要走出去看看更高的世界&#xff1f;…

华三(H3C)T1020 IPS服务器硬件监控指标解读

在日益复杂的网络环境中&#xff0c;服务器的稳定运行对于保障业务的连续性和安全性至关重要。华三&#xff08;H3C&#xff09;T1020 IPS作为一款高性能的入侵防御系统&#xff0c;其运行状态和性能监控显得尤为重要。监控易作为一款专业的监控软件&#xff0c;为华三T1020 IP…

【Unity3D插件】Unity3D HDRP Outline高亮发光轮廓描边插件教程

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 最近用Unity3D的HDRP&#xff08;高清渲染管…

数据结构-7.Java. 对象的比较

本篇博客给大家带来的是java对象的比较的知识点, 其中包括 用户自定义类型比较, PriorityQueue的比较方式, 三种比较方法...... 文章专栏: Java-数据结构 若有问题 评论区见 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 .…

OpenCV相机标定与3D重建(3)校正鱼眼镜头畸变的函数calibrate()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::fisheye::calibrate 函数是 OpenCV 中用于校正鱼眼镜头畸变的一个重要函数。该函数通过一系列棋盘格标定板的图像来计算相机的内参矩阵和畸变…

GitLab使用操作v1.0

1.前置条件 Gitlab 项目地址&#xff1a;http://******/req Gitlab账户信息&#xff1a;例如 001/******自己的分支名称&#xff1a;例如 001-master&#xff08;注&#xff1a;master只有项目创建者有权限更新&#xff0c;我们只能更新自己分支&#xff0c;然后创建合并请求&…

机器学习阶段学习Day31

KNN分类算法 KNN算法原理 根据K个邻居样本来判断当前样本属于哪个类别&#xff1a;K个最相似邻居中大多数所属类别即为当前样本的类别。但是对于数据量巨大或者高纬度的数据样本不太合适&#xff0c;数据量大的数据样本需要进行大量计算&#xff0c;而高纬度数据计算距离不具…

【Android、IOS、Flutter、鸿蒙、ReactNative 】实现 MVP 架构

Android Studio 版本 Android Java MVP 模式 参考 模型层 model public class User {private String email;private String password;public User(String email, String password) {this.email = email;this.password = password;}public String getEmail() {return email;}…

uniapp发布android上架应用商店权限

先看效果&#xff1a; 实现原理&#xff1a; 一、利用uni.addInterceptor的拦截器&#xff0c;在一些调用系统权限前拦截&#xff0c;进行弹窗展示&#xff0c;监听确定取消实现业务逻辑。 二、弹窗是原生nativeObj进行drawRect绘制的 三、权限申请调用使用的 plus.android.…

VSCode【下载】【安装】【汉化】【配置C++环境】【运行调试】(Windows环境)

目录 一、VSCode的下载 & 安装 二、汉化 三、配置C 一、VSCode的下载 & 安装 Download Visual Studio Code - Mac, Linux, Windowshttps://code.visualstudio.com/Download 注意&#xff01;&#xff01;&#xff01;【不建议下载User版本&#xff0c;下载System版本】…

Diving into the STM32 HAL-----DAC笔记

根据所使用的系列和封装&#xff0c;STM32微控制器通常只提供一个具有一个或两个专用输出的DAC&#xff0c;除了STM32F3系列中的少数零件编号实现两个DAC&#xff0c;第一个具有两个输出&#xff0c;另一个只有一个输出。STM32G4 系列的一些较新的 MCU 甚至提供多达 5 个独立的…

OpenCV和Qt坐标系不一致问题

“ OpenCV和QT坐标系导致绘图精度下降问题。” OpenCV和Qt常用的坐标系都是笛卡尔坐标系&#xff0c;但是细微处有些不同。 01 — OpenCV坐标系 OpenCV是图像处理库&#xff0c;是以图像像素为一个坐标位置&#xff0c;即一个像素对应一个坐标&#xff0c;所以其坐标系也叫图像…

STM32完全学习——系统时钟设置

一、时钟框图的解读 首先我们知道STM32在上电初始化之后使用的是内部的HSI未经过分频直接通过SW供给给系统时钟&#xff0c;由于内部HSI存在较大的误差&#xff0c;因此我们在系统完成上电初始化&#xff0c;之后需要将STM32的时钟切换到外部HSE作为系统时钟&#xff0c;那么我…

Java NIO 核心知识总结

在学习 NIO 之前&#xff0c;需要先了解一下计算机 I/O 模型的基础理论知识。还不了解的话&#xff0c;可以参考我写的这篇文章&#xff1a;Java IO 模型详解。 一、NIO 简介 在传统的 Java I/O 模型&#xff08;BIO&#xff09;中&#xff0c;I/O 操作是以阻塞的方式进行的。…