当前位置: 首页 > news >正文

智能合约安全新范式,超越 `require`和`assert`

智能合约安全新范式,超越 require_assert

摘要

不要只为特定的函数写 require 语句;为你的协议写 require 语句。函数遵循检查(requirements)-生效(Effects)-交互(INteractions)+协议不变性(Invariants)或 FREI-PI 模式可以帮助你的合约更加安全,因为它迫使开发人员除了关注函数级别的安全之外,还要关注协议级别的不变性。

动机

2023 年 3 月,Euler Finance 被黑客攻击,损失 2 亿美元。Euler Finance 是一个借贷市场,用户可以存入抵押品并以其为抵押进行借款。它有一些独特的功能,实际上他们是一个可与 Compound Finance 和 Aave 媲美的借贷市场。
你可以阅读关于这个黑客的事后总结这里。它的主要内容是在一个特定的函数中缺少健康检查,允许用户打破借贷市场的基础不变性。

基础不变性(Fundamental Invariants)

大多数 DeFi 协议的核心都有一个不变性,即程序状态的一个属性,它被期望永远是真的。也可能有多个不变性,但一般来说,它们是围绕着一个核心思想建立的。这里是一些例子:

  • 如在借贷市场中:用户不能采取任何行动,使任何账户处于不安全或更不安全的抵押品仓位("更不安全"意味着它已经低于最低安全阈值,因此不能进一步提取)。
  • AMM DEX 中:x * y == k,x + y == k,等等。
  • 流动性挖矿抵押中: 用户应该只能提取他们存入的抵押代币数量。

Euler Finance 出错的地方不一定是他们增加了功能,没有写测试,或者没有遵循传统的最佳实践。他们对升级进行了审计,并有测试,但还是被漏掉了。核心问题是他们忘记了借贷市场的核心不变性(审计人员也是如此!)。
注:我不是要挑刺 Euler,他们是一个有才华的团队,但这是一个最近的案例。

问题的核心

你可能在想 “嗯,没错。这就是他们被黑的原因;他们忘了一个 require 语句”。是也不是。
为什么他们会忘记 require 语句呢?

检查-生效-交互 不够好

推荐给 solidity 开发者使用的一个常见模式是 Checks-Effects-Interactions(检查-生效-交互)模式。它对于消除与重入有关的错误非常有用,而且通常会增加开发人员去执行输入验证的的数量。但是,它容易出现只见树木不见森林的问题。
它教给开发人员的是:“首先我写我的 require 语句,然后我做生效,然后也许我做任何交互,然后我就安全了”。问题是,通常情况下,它变成了检查和效果的混合体–不错吧?交互仍然是最后的,所以重入性不是一个问题。但它迫使用户关注更具体的功能和个别的状态转换,而不是全局的、更广泛的背景。这就是说:
仅仅是检查-生效-交互模式就会使开发者忘记他们协议的核心不变性
对于开发者来说,它仍然是一个出色的模式,但总是应该确保(服务于)协议的不变性(说真的,你还是应该使用 CEI!)。

正确做法:FREI-PI 模式

以 dYdX 的 SoloMargin 合约(源码)中的这个片段为例,它是借贷市场和杠杆交易合约。这是一个很好的例子,我称之为 功能检查-生效-交互+协议不变性(Function Requirements-Effects-Interactions + Protocol Invariants )模式,或 FREI-PI 模式。
因此,我相信这是早期借贷市场中唯一没有任何市场相关漏洞的借贷市场。Compound 和 Aave 没有直接出现问题,但他们的分叉代码有关于过问题。而 bZx 则被黑了多次。
检查下面的代码,注意以下的抽象概念:

  1. 检查输入参数(_verifyInputs)。
  2. 动作(数据转换,状态操作)
  3. 检查最终状态(_verifyFinalState)。
function operate(Storage.State storage state,Account.Info[] memory accounts,Actions.ActionArgs[] memory actions)public{Events.logOperation();_verifyInputs(accounts, actions);(bool[] memory primaryAccounts,Cache.MarketCache memory cache) = _runPreprocessing(state,accounts,actions);_runActions(state,accounts,actions,cache);_verifyFinalState(state,accounts,primaryAccounts,cache);}

仍然执行常用的 Checks-Effects-Interactions。值得注意的是,带有额外 检查 的 检查-生效-交互 并不等同于 FREI-PI–它们是相似的,但服务于根本不同的目标。因此,开发者应该认为它们是不同的:FREI-PI 作为一个更高的抽象,旨在实现协议安全,而 CEI 旨在实现功能安全。
这个合约的结构真的很有趣–用户可以在一连串的行动中执行他们想要的行动(存款、借款、交易、转让、清算等)。想存入 3 个不同的代币,提取第 4 个,并清算一个账户?这是一个单一的调用。
这就是 FREI-PI 的力量:用户可以在协议内做任何他们想做的事情,只要核心借贷市场的不变性在调用结束时成立:一个用户不能采取任何行动,将任何账户置于不安全或更不安全的抵押品仓位。对于这个合约,这是在verifyFinalState 中执行的,检查每个受影响账户的抵押情况,确保协议比交易开始时更好。
该函数中包括一些额外的不变性,这些不变性是对核心不变性的补充,有助于实现关闭市场等附属功能,但
真正_保持协议安全的是核心检查。

以实体为中心的 FREI-PI

FREI-PI 的另一个问题是以实体为中心的概念。以一个借贷市场和假定的核心不变性为例:

一个用户不能采取任何行动,将任何账户置于不安全或更不安全的抵押品仓位

从技术上讲,这不是唯一的不变性,但它是针对用户实体的(它仍然是核心协议不变性,通常用户不变性是核心协议不变性)。借贷市场通常也会有 2 个额外的实体:

  1. 预言机
  2. 管理/治理

每一个额外的不变性都会使协议更加难以保障,因此越少越好。

预言机

对于预言机,以 1.3 亿美元的Cream Finance 漏洞为例。预言机实体的核心不变性:

预言机提供准确且(相对)实时的信息

事实证明,用 FREI-PI 在运行时验证预言机是很棘手的,但是可以做到,需要一些预先考虑。一般来说,Chainlink 是一个很好的选择,可以主要依靠,满足大部分的不变性。在极少数的操纵或意外情况下,有一些保障措施可能是有益的,这些保障措施可以减少灵活性,而有利于准确性(比如检查最后知道的值是否比当前值大百分数百)。同样,dYdX 的 SoloMargin 系统在他们的 DAI 预言机方面做得很好, 这里是代码(如果你看不出来,我认为这是历史上写得最好的复杂智能合约系统)。
关于预言机评估的更多内容,以及突出 Euler 团队的能力,他们写了一篇关于计算操纵 Uniswap V3 TWAP 预言机价格的好文章。

管理/治理

为管理实体创建不变性是最棘手。这主要是由于他们的大部分作用是去改变现有的其他不变性。也就是说,如果你能避免使用管理角色,你应该这样做。
从根本上说,一个管理实体的核心不变性可能是:

管理员应该在当且仅当在其他的不变性或需要特意移除或修改不变性时才采取行动。

解读:管理员可以做一些应该结果不会破坏不变性的事情,除非他们为了保护用户的资金而大幅改变事情(例如:将资产转移到救援合约中是对不变性的移除)。管理员也应该被认为是一个用户,所以核心借贷市场的用户不变性也应该对他们成立(意味着他们不能对其他用户或协议进行攻击)。目前,一些管理员的行为不可能在运行时通过 FREI-PI 进行验证,但如果在其他地方有足够强大的不变性,希望大多数问题可以得到缓解。我说目前,因为人们可以想象使用 zk 证明系统可能会检查合约的整个状态(每个用户、每个预言机等)。
作为一个管理员破坏不变性的例子,以发生在 2022 年 8 月的borked the cETH market的 Compound 治理行动为例。从根本上说,这次升级破坏了 Oracle 的不变性:Oracle 提供准确和(相对)实时的信息。由于功能的缺失,Oracle 可以提供不对的信息。一个运行时的 FREI-PI 验证,检查受影响的 Oracle 能否提供实时信息,可以防止升级的发生这样的情况。这可以纳入_setPriceOracle,检查所有资产是否收到实时信息。FREI-PI 对管理角色的好处是,管理角色对价格相对不敏感(或者至少应该是这样),所以更多的 Gas 使用量不应该是个大问题。

复杂是危险的

因此,虽然最重要的不变性是协议的核心不变性,但也可以有一些以实体为中心的不变性,这些不变性必须为核心不变性所持有。但是,最简单(和最小)的不变性集可能是最安全的。简单就是好的一个光辉榜样是 Uniswap …

为什么 Uniswap 从来没有被黑过(大概)

AMMs 可以有任何 DeFi 原语中最简单的基本不变性:tokenBalanceX * tokenBalanceY == k(例如常量乘积模型)。Uniswap V2 中的每个函数都是围绕这个简单的不变性:

  1. Mint:添加到 k 中
  2. Burn:从 k 中减去
  3. Swap:转移 x 和 y,不动 k。
  4. Skim:重新调整 tokenBalanceX * tokenBalanceY,使其等于 k,移除多余的部分。

Uniswap V2 的安全秘诀:核心是一个简单的不变性,所有功能都是为它服务的。唯一可以争论的其他实体是治理,它可以打开一个收费开关,这并不触及核心不变性,只是代币余额所有权的分配。他们的安全声明中的这种简单性是 Uniswap 从未被黑过的原因。简单其实并不是对 Uniswap 的智能合约的优秀开发者的轻视,相反需要出色的工程师来找到简单性。

Gas 问题

我的 Twitter 上已经充满了优化论者关于这些检查是不必要的和低效的恐怖和痛苦的尖叫声。关于这个问题有两点:

  1. 你知道还有什么是低效的吗?不得不通过 etherscan 向Laurence朝鲜黑客发送信息,使用 ETH 转账,并威胁说 FBI 会介入。
  2. 你可能已经从存储中加载了所有需要的数据,所以在调用结束时,只是对这些热数据加一点点 require 检查。你想让你的协议贵那么一点忽略不计的费用,还是让它死于非命?

如果成本过高,请重新考虑核心变量,并尝试简化。

这对我来说意味着什么?

作为一个开发者,要在开发过程中尽早地定义并表达出核心不变性。作为一个具体的建议:让自己写的第一个函数是_verifyAfter,在每次调用你的合约后验证你的不变性。把它放在你的合约中,并在那里进行部署。用更广泛的不变性测试来补充这个不变性(以及其他以实体为中心的不变性),这些测试在部署前就被检查过了(Foundry guide)。
瞬时存储开启了一些有趣的优化和改进,Nascent 将对此进行实验–我建议你考虑如何将瞬时存储作为一种工具,以实现更好的跨调用上下文更安全。
在这篇文章中,没有花太多时间在 FREI-PI 模式的介绍输入验证,但这也是非常重要的。定义输入的边界是一项具有挑战性的任务,以避免溢出和类似情况。可以考虑查看并关注我们的工具的进展:pyrometer(目前处于测试阶段,请给我们一个星星)。它可以深入了解并帮助找到你可能没有进行输入验证的地方。

结论

在任何朗朗上口的缩写(FREI-PI)或模式名称之上,真正重要的一点是:
在你的协议的核心不变性中找到简单性。并拼命工作以确保它永远不会被破坏(或在它被破坏之前就被捕获)。

相关文章:

智能合约安全新范式,超越 `require`和`assert`

智能合约安全新范式,超越 require_assert 摘要 不要只为特定的函数写 require 语句;为你的协议写 require 语句。函数遵循检查(requirements)-生效(Effects)-交互(INteractions)协议不变性(Invariants)或 FREI-PI 模式可以帮助你的合约更加安全&#x…...

【ESP-S3-BOX-Lite花屏问题】:Github下载源码(出厂源码factory_demo)编译调试到ESP-S3-BOX-Lite中出现花屏现象

项目场景: 最近拿到了一块乐鑫的 ESP-S3-BOX-Lite (esp-box: ESP-BOX 是乐鑫信息科技) 详细资料(esp32_s3_box_lite) 版本信息 ESP-BOX依赖的 ESP-IDF分支信息支持状态master> release/v5.1 commit id: 22cfbf3…...

Redis集群3.2.11离线安装详细版本(使用Ruby)

1.安装软件准备 1.Redis版本下载 Index of /releases/http://download.redis.io/releases/ 1.2gcc环境准备 GCC(GNU Compiler Collection,GNU编译器套件)是一套用于编译程序代码的开源编译器工具集。它的主要用途是将高级编程语言(如C、C++、Fortran等)编写的源代码转换…...

Ansible自动化运维

目录 前言 一、概述 常见的开源自动化运维工具比较 二、ansible环境搭建 三、ansible模块 (一)、hostname模块 (二)、file模块 (三)、copy模块 (四)、fetch模块 &#xff…...

MSTP + Eth-Trunk配置实验 华为实验手册

1.1 实验介绍 1.1.1 关于本实验 以太网是当今现有局域网LAN(Local Area Network)采用的最通用的通信协议标准,以太网作为一种原理简单、便于实现同时又价格低廉的局域网技术已经成为业界的主流。 本实验主要介绍了LAN网络中的Eth-Trunk技术…...

滚动菜单 flutter

想实现这个功能: 下面的代码可以实现: import package:flutter/material.dart;void main() > runApp(MyApp());class MyApp extends StatelessWidget {static const String _title Flutter Code Sample;overrideWidget build(BuildContext context)…...

javaee springMVC数字类型转换之通过注解的方式

po 在属性上增加注解 NumberFormat(pattern “#,#.#”) package com.test.pojo;import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.NumberFormat;import java.util.Date;public class Users {private int uid;pr…...

SQL中CASE的用法

在SQL中,CASE语句是一种条件表达式,用于根据条件执行不同的操作。它有两种形式:简单CASE表达式和搜索CASE表达式。 简单CASE表达式的语法如下: CASE expressionWHEN value1 THEN result1WHEN value2 THEN result2...ELSE result …...

自己的碎碎念集合

自己的碎碎念集合 2023-09-07 c++叠加三目运算符闰年计算法2023-08-13 一个小题目 A+B problem一、问题及解答关碍总结2023-07-26 C的2至36进制转换函数一、itoa()函数的示例代码总结2023-07-19 平面坐标下判断三角形以及输出周长和面积一. 基本知识总结2023-06-25 达芬奇去除白…...

暂定名「码道功成:Coder启示录」

听人劝、吃饱饭,奉劝各位小伙伴,不要订阅该文所属专栏。 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 跨域学习者,从事过全栈研发、产品经理等工作,现任研发部门 CTO 。荣誉:2022年度博客之星Top4、博客专家认证、全栈领域优质创作者、新星计划导师,“星荐官共赢计…...

Apache HTTPD (CVE-2017-15715)换行解析漏洞复现

Apache HTTPD 换行解析漏洞 CVE-2017-15715漏洞简介 组件版本漏洞名称 Apache HTTPD 换行解析漏洞(CVE-2017-15715) 漏洞描述 ​ Apache HTTPD是一款HTTP服务器,它可以通过mod_php来运行PHP网页。其2.4.0~2.4.29版本中存在一个解析漏洞&…...

Spring Boot集成JasperReport生成文档

由于工作需要,要实现后端根据模板动态填充数据生成PDF文档,通过技术选型,使用Ireport5.6来设计模板,结合JasperReports5.6工具库来调用渲染生成PDF文档。 一、使用Ireport designer 5.6设计模板 ireport的使用由于时间关系不便多…...

02-Tomcat打破双亲委派机制

上一篇:01-从JDK源码级别剖析JVM类加载机制 Tomcat 如果使用默认的双亲委派类加载机制行不行? 我们思考一下:Tomcat是个web容器, 那么它要解决什么问题: 一个web容器可能需要部署两个应用程序,不同的应用…...

怎么理解flink的异步检查点机制

背景 flink的checkpoint监控页面那里有两个指标Sync Duration 和Async Duration,一个是开始进行同步checkpoint所需的时间,一个是异步checkpoint过程所需的时间,你是否也有过疑惑,是否只是同步过程中的时间才会阻塞正常的数据处理…...

SpringMVC <url-pattern/>解读

1. < url-pattern/>的值 (1).使用拓展名的方式&#xff0c;语法*.xxx&#xff0c;xxx是自定义的拓展名&#xff0c;常用的方式*.do&#xff0c;*.action,不能使用*.jsp. (2).使用斜杠 "/"当项目中使用了 / &#xff0c;他会替代tomcat中的default。导致所有的…...

大学毕业设计的益处:培养实践能力、深入专业领域、展示自信与建立联系

大学生做毕业设计有许多好处&#xff0c;以下是一些主要的原因和好处&#xff1a; 实践应用能力&#xff1a;毕业设计通常需要学生将所学的知识和技能应用到一个具体的项目中&#xff0c;这有助于他们将理论知识转化为实际应用能力。 独立思考和解决问题&#xff1a;毕业设计要…...

ChatGPT:概述Vue.js中data函数初始化和created钩子函数调用的顺序和问题解决方法

ChatGPT&#xff1a;概述Vue.js中data函数初始化和created钩子函数调用的顺序和问题解决方法 我将输入一段Vue代码&#xff0c;请你记住&#xff1a; created() {console.log(this.queryInfo)this.getClueList();},data() {return {allQueryInfo: {str: ,//线索标题查询信息},/…...

SpringBoot【基础篇】

一、快速上手 按照要求&#xff0c;左侧选择web&#xff0c;然后在中间选择Spring Web即可&#xff0c;选完右侧就出现了新的内容项&#xff0c;这就表示勾选成功了 关注&#xff1a;此处选择的SpringBoot的版本使用默认的就可以了&#xff0c;需要说一点&#xff0c;SpringBo…...

Vuex - state 状态(获取和使用共享数据)

文章目录 一、state是什么&#xff1f;二、state状态的作用三、如何使用store数据呢&#xff1f;使用数据的两种方式&#xff1a;1. 通过store 直接访问2. 通过辅助函数访问(简化) 一、state是什么&#xff1f; state是状态&#xff08;数据&#xff09; &#xff0c; 类似于v…...

tcp连接+套接字编程

tcp头部 tcp端口号 TCP的连接是需要四个要素确定唯一一个连接&#xff1a;&#xff08;源IP&#xff0c;源端口号&#xff09; &#xff08;目地IP&#xff0c;目的端口号&#xff09; 所以TCP首部预留了两个16位作为端口号的存储&#xff0c;而IP地址由上一层IP协议负责传递 源…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...