智能合约安全新范式,超越 `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 则被黑了多次。
检查下面的代码,注意以下的抽象概念:
- 检查输入参数(_verifyInputs)。
- 动作(数据转换,状态操作)
- 检查最终状态(_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.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 中的每个函数都是围绕这个简单的不变性:
- Mint:添加到 k 中
- Burn:从 k 中减去
- Swap:转移 x 和 y,不动 k。
- Skim:重新调整 tokenBalanceX * tokenBalanceY,使其等于 k,移除多余的部分。
Uniswap V2 的安全秘诀:核心是一个简单的不变性,所有功能都是为它服务的。唯一可以争论的其他实体是治理,它可以打开一个收费开关,这并不触及核心不变性,只是代币余额所有权的分配。他们的安全声明中的这种简单性是 Uniswap 从未被黑过的原因。简单其实并不是对 Uniswap 的智能合约的优秀开发者的轻视,相反需要出色的工程师来找到简单性。
Gas 问题
我的 Twitter 上已经充满了优化论者关于这些检查是不必要的和低效的恐怖和痛苦的尖叫声。关于这个问题有两点:
- 你知道还有什么是低效的吗?不得不通过 etherscan 向
Laurence朝鲜黑客发送信息,使用 ETH 转账,并威胁说 FBI 会介入。 - 你可能已经从存储中加载了所有需要的数据,所以在调用结束时,只是对这些热数据加一点点 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模块 ÿ…...
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).使用拓展名的方式,语法*.xxx,xxx是自定义的拓展名,常用的方式*.do,*.action,不能使用*.jsp. (2).使用斜杠 "/"当项目中使用了 / ,他会替代tomcat中的default。导致所有的…...
大学毕业设计的益处:培养实践能力、深入专业领域、展示自信与建立联系
大学生做毕业设计有许多好处,以下是一些主要的原因和好处: 实践应用能力:毕业设计通常需要学生将所学的知识和技能应用到一个具体的项目中,这有助于他们将理论知识转化为实际应用能力。 独立思考和解决问题:毕业设计要…...
ChatGPT:概述Vue.js中data函数初始化和created钩子函数调用的顺序和问题解决方法
ChatGPT:概述Vue.js中data函数初始化和created钩子函数调用的顺序和问题解决方法 我将输入一段Vue代码,请你记住: created() {console.log(this.queryInfo)this.getClueList();},data() {return {allQueryInfo: {str: ,//线索标题查询信息},/…...
SpringBoot【基础篇】
一、快速上手 按照要求,左侧选择web,然后在中间选择Spring Web即可,选完右侧就出现了新的内容项,这就表示勾选成功了 关注:此处选择的SpringBoot的版本使用默认的就可以了,需要说一点,SpringBo…...
Vuex - state 状态(获取和使用共享数据)
文章目录 一、state是什么?二、state状态的作用三、如何使用store数据呢?使用数据的两种方式:1. 通过store 直接访问2. 通过辅助函数访问(简化) 一、state是什么? state是状态(数据) , 类似于v…...
tcp连接+套接字编程
tcp头部 tcp端口号 TCP的连接是需要四个要素确定唯一一个连接:(源IP,源端口号) (目地IP,目的端口号) 所以TCP首部预留了两个16位作为端口号的存储,而IP地址由上一层IP协议负责传递 源…...
OpenCV(三十四):轮廓外接最大、最小矩形和多边形拟合
目录 1.轮廓外接最大矩形boundingRect() 2.轮廓外接最小矩形minAreaRect() 3.轮廓外接多边形approxPolyDP() 1.轮廓外接最大矩形boundingRect() Rect cv::boundingRect ( InputArray array ) array:输入的灰度图像或者2D点集,数据类型为vector<Point>或者M…...
Kafka3.0.0版本——消费者(offset的默认维护位置)
目录 一、offset的默认维护位置1.1、offset的默认维护位置概述1.2、offset的默认维护位置图解 二、消费者offset的案例 一、offset的默认维护位置 1.1、offset的默认维护位置概述 Kafka0.9版本之前,consumer默认将offset保存在Zookeeper中。从Kafka0.9版本开始&am…...
Wireshark技巧[监听串口包]
监听串口包 本文摘录于:https://blog.csdn.net/qq_20405005/article/details/79652927只是做学习备份之用,绝无抄袭之意,有疑惑请联系本人! 这里要保证安装了USBpcap: 打开USBpcap后一半都要输入过滤条件,否则USB太多数据了,比如…...
安全运营中心即服务提供商评估
如果组织当前没有自己的安全运营中心(SOC),那么可能需要考虑如何在不从头开始构建的情况下获得安全运营中心(SOC)。自己构建安全运营中心(SOC)的费用可能会非常昂贵,考虑到工作人员全天候运营的配置成本,就更是如此。在过去几年中,…...
算法通关村第十三关——幂运算问题解析
前言 幂运算为常见的数学运算,形式为 a b a^b ab ,其中a为底数,b为指数, 力扣中,幂运算相关的问题主要是判断一个数是不是特定正整数的整数次幂,以及快速幂的处理。 1.求2的幂 力扣231题,给…...
Python 之使用Numpy库来加载Numpy(.npy)文件并检查其内容
文章目录 总的介绍data.dtypedata.shapedata.ndimdata.size 总的介绍 要判断一个Numpy(.npy)文件的数据集类型,你可以使用Python中的Numpy库来加载该文件并检查其内容。以下是一些常见的步骤: 导入Numpy库: 首先&…...
C#学习系列之UDP同端口收发问题
C#学习系列之UDP同端口收发问题 前言解决办法关于JoinMulticastGroup总结 前言 想测试自己的程序问题,建立了两个UDP程序,一个往端口中接到数就传出去,另一个从这个端口接数据来解析。 出现的问题是 每次打开端口,另一个程序就无…...
SpringMVC之文件上传下载以及jrebel的使用
目录 一、文件上传 1.1 导入依赖 1.2 配置文件上传解析器 1.3 配置服务器存放文件地址 1.3.1 点击编辑Configurations 1.3.2 将项目部署至tomcat服务器上 1.3.3 配置相对路径 1.4 导入PropertiesUtil工具类 1.5 编写resource.properties 1.6 添加sql 1.7 编写PageCo…...
基于Fomantic UI Web构建 个人导航站点网站源码 网站技术导航源码
BYR-Navi-master好看有个性的网站技术导航源码 该网站基于Fomantic UI Web框架构建,整个项目的设计和构建具有高度的配置和定制灵活性。 整体风格比较适合个人导航站点使用 搜索框输入关键词后,点击上方搜索引擎图标可跳转打开对应搜索引擎搜索结果&am…...
DRF02-请求响应与路由
文章目录 1. http请求响应1.1. 请求与响应1.1.1 Request1.1.1.1 常用属性1).data2).query_params3)request._request基本使用1.1.2 Response1.1.2.1 构造方式1.1.2.2 response对象的属性1).data2).status_code3).content1.1.2.3 状态码1)信息告知 - 1xx2)成功 - 2xx3)…...
长沙企业建站在线咨询/郴州网站定制
诺基亚808 PureView 凭借其4100万像素摄像头获得了2012影像界TIPA大奖,其超高的像素几乎秒杀市面上所有单反,不过官方宣称808 PureView在印度和俄罗斯首发,国内还不知道要等到什么时候。808 PureView的照片大家是看多了,但是对于其…...
网站集约化建设汇报/手机百度搜索
文章目录前言一、大驼峰法(帕斯卡命名法)二、小驼峰法三、其他前言 驼峰命名法,是指混合使用大小写字母构成变量和函数名字。在Java开发中,建议使用驼峰命名法,增强代码的识别性和可读性。 一、大驼峰法(帕…...
一步一步网站建设教程/百度怎么做广告推广
http://www.hcharts.cn/转载于:https://www.cnblogs.com/missmiao/p/4772786.html...
网站建设的步骤有哪些/网站快速收录的方法
mock:能进行后端数据模拟,生成随机数据,拦截Ajax请求 一、 创建好一个项目 1.安装axios 2.安装mockjs 3.html写一个简单的登录 <div class"home"><p><input type"text" placeholder"请输入账号" /></p>&…...
西部数码网站管理助手 数据库/昆明自动seo
使用内存监测工具 DDMS –> Heap操作步骤1.启动eclipse后,切换到DDMS透视图,并确认Devices视图、Heap视图都是打开的,没打开的直接Window>ShowView>自己选2.将手机通过USB链接至电脑,链接时需要确认手机是处于“USB调试”…...
网页设计的好处/专业排名优化工具
转自 https://blog.csdn.net/u012702547/article/details/77823434 这个系列我感觉真的太好了,可以一步一步的了解spring cloud 的搭建以及更深层次的东西,对想学这门技术的朋友真的入门特别的快,感谢这位大哥的分享,我也会持续的…...