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

区块链智能合约( solidity) 安全编程

引言:本文由天玄链开源开发者提供,欢迎报名公益天玄链训练营

https://blockchain.163.com/trainingCamp

一、重入和竞态

重入和竞态在solidity 编程安全中会多次提及,历史上也造成了重大的损失。

1.1 问题分析

竞态的描述不严格,竞态是在并发编程中的概念。而以太坊智能合约是单线程运行的。不存在并发。它的问题来自于重入。

我们在实现智能合约无法做到可重入的,所以就要添加重入的保护。一般情况下,重入问题来自于fallback 或者 recevie 方法,因为以太坊转账是最常用的功能。

当然如果调用了其他不安全的合约一样有这个问题。

1.2 可重入保护

一般的解决方案,“检查-生效-交互”,这个方法是现在常用的,也是推荐使用的。

function untrustedWithdraw(address recipient) public {

    uint amountToWithdraw = userBalances[recipient];

    rewardsForA[recipient] = 0;

    if (!(recipient.call.value(amountToWithdraw)())) { throw; }

}

  

function untrustedGetFirstWithdrawalBonus(address recipient) public {

    if (claimedBonus[recipient]) { throw; } // 检查

    claimedBonus[recipient] = true;//生效

    rewardsForA[recipient] += 100;

    untrustedWithdraw(recipient); // 交互

}

另外,既然它表现的像多线程并发。还有一种解决方案,就是加锁。openzeppelin 中 ReentrancyGuard合约中的nonReentrant modifier也是阻止重入的一种方法。

但是需要注意的是,这个modifier  只能对单个方法起作用,需要在所有状态相关方法上添加才能防止交叉重入。

综上,“检查-生效-交互” 推荐使用来防止重入。

 1.3 显示标示untrust

在调用不安全外部合约的方法时,需要将该方法标示为untrust。同时,调用该untrust 的方法也应该是untrust。

对待untrust 方法规范是,首先处理完内部状态,最后调用untrust 方法。向外部地址转账,显然也是调用了外部合约方法,属于untrust 调用

二、安全转账

在uniswap中有很多转账的范例,比如下面的代码,将常用的ERC20 转账,注意,在safeTransferETH 中,它使用了to.call 而不是 to.transfer,因为而.send 或者 .transfer 是发送固定gas,

 solidity 升级后,一些操作码的gas 可能有变化。这就导致之前的fallback 方法可能会失败。对建立在uniswap上的生态造成影响。

但是直接使用.call 有很多风险,比如要校验返回值,再比如重入攻击问题。所以尽量使用成熟的范式,是增强代码安全的有效手段。这里可能引入的重入风险,我们后面再单独分析。

function safeTransfer(

    address token,

    address to,

    uint256 value

) internal {

    // bytes4(keccak256(bytes('transfer(address,uint256)')));

    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));

    require(

        success && (data.length == 0 || abi.decode(data, (bool))),

        'TransferHelper::safeTransfer: transfer failed'

    );

}

function safeTransferFrom(

    address token,

    address from,

    address to,

    uint256 value

) internal {

    // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));

    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));

    require(

        success && (data.length == 0 || abi.decode(data, (bool))),

        'TransferHelper::transferFrom: transferFrom failed'

    );

}

function safeTransferETH(address to, uint256 value) internal {

    (bool success, ) = to.call{value: value}(new bytes(0));

    require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');

}

三、以太发送方法

3.1 常用方法

常用的两种方法,send, transfer

send与transfer对比简析

相同之处

(1)均是向address发送ETH(以Wei做单位)

(2)发送的同时传输2300gas(gas数量很少,只允许接收方合约执行最简单的操作)

不同之处

(1)send执行失败返回false,transfer执行失败则会throw。这也就意味着使用send时一定要判断是否执行成功。

推荐

(1)默认情况下最好使用transfer(因为内置了执行失败的处理)

安全推荐是transfer,相信大家都知道。那么为什么transfer 更好,在于它是更高级的方法,封装了校验返回值,并抛出异常。

3.2 引申一下

我想引申一点是,在我们写方法的时候,当校验时,应该使用require 而不是 if,使用if 使得方法没有完成必要逻辑,而交易成功。这其实有隐患的。

除非你非常清楚这个差别,并认为只有if 才能满足函数需求。

比如有一个编程模式做频率检查,模式设计推荐的是

modifier enabledEvery(uint t) {   

  if (now >= enabledAt) {

    enabledAt = now + t;

    _;

  }

}

其实这个设计就有我上面说的问题,虽然达到了限制频率的目的,但是整个交易时成功的。正常使用就会有很多困惑,一旦被集成到其他合约,就会造成攻击的隐患。

建议是使用require,一旦失败,交易会revert,而且原因清晰。

modifier enabledEvery(uint t) {

  require(now >= enabledAt,"too freq, wait a minute");

  enabledAt = now + t;

  _;

3.3 转账成功的条件

如果对方是合约地址,那么它需要具备receive 方法,或者payable 的fallback 方法。如果两者都没有则转账失败。但是从另一面说,没有这两个方法不代表不能收取以太。

这还是要从概念上区分一下。

这就引申出两个问题,

3.3.1 合约为用户转账

要考虑到失败的可能。尽量使用pull 而不是push 方法。也就是让用用户发起withdraw收取以太,而不是合约dispatch。 

3.3.2 合约需要收帐的。

即便没有设置payable 的fallback,和 receive 方法,你依然不能阻止绕过收款方法,直接转账给合约,使得合约balance 跟合约内账本对不上。

所以,业务逻辑要使用自己的账本。

3.3.3 非标准ERC20 的影响

业务逻辑建立在自己的账本上就够了吗?对于有些token 虽然符合ERC 标准,但是具体实现却又做了一些改动,比如有个项目做了转账收手续费的操作,

在转账过程中收取。也就是实际到账比交易执行的要少,如果只关注交易是否成功,然后记账是造成漏洞,所以这种情况,还需要去查balance 的变化。

以上是在转账过程需要注意的,不仅要合约记录账本,还需要核对balance,以保证业务逻辑没有漏洞。

当然如果业务确信没有此类问题。可以简化,比如只涉及USDT 的入账,那么可以不考虑3.3.3。

四、慎用tx.origin

永远不要 tx.origin 用于授权,另一个合约可以有一个方法来调用你的合约(例如,用户有一些资金)并且你的合约将授权该交易,因为你的地址位于tx.origin.

contract MyContract {address owner;function MyContract() public {owner = msg.sender;}function sendTo(address receiver, uint amount) public {require(tx.origin == owner);(bool success, ) = receiver.call.value(amount)("");require(success);}}contract AttackingContract {MyContract myContract;address attacker;function AttackingContract(address myContractAddress) public {myContract = MyContract(myContractAddress);attacker = msg.sender;}function() public {myContract.sendTo(attacker, msg.sender.balance);}}

这是最常见的错误。

如果我们用tx.origin 能用来干嘛?我们先引申一下。EOA 的概念。

4.1 如何判断一个账户是EOA 账户而不是contract。

一种做法是如下,很多业务是这么写的。但其实是有问题。某些情况会失效,比如constructor中。

/** @dev Modifier requiring sender to be EOA.  This check could be bypassed by a malicious

 *  contract via initcode, but it takes care of the user error we want to avoid.

 */

modifier onlyEOA() {

    // Used to stop deposits from contracts (avoid accidentally lost tokens)

    require(!Address.isContract(msg.sender), "Account not EOA");

    _;

}

那么如何判断EOA 呢,这里就用到了tx.origin. 

    modifier onlyEOA() {

        // Used to stop deposits from contracts (avoid accidentally lost tokens)

        require(tx.origin == msg.sender, "Account not EOA");

        _;

    }

  

相关文章:

区块链智能合约( solidity) 安全编程

引言:本文由天玄链开源开发者提供,欢迎报名公益天玄链训练营 https://blockchain.163.com/trainingCamp 一、重入和竞态 重入和竞态在solidity 编程安全中会多次提及,历史上也造成了重大的损失。 1.1 问题分析 竞态的描述不严格&#xf…...

GUNS搭建

一、准备工作 源码下载: 链接: https://pan.baidu.com/s/1bJZzAzGJRt-NxtIQ82KlBw 提取码: criq 官方文档 二、导入代码 1、导入后端IDE 导入完成需要,需要修改yml文件中的数据库配置,改成自己的。 2、导入前端IDE 我是用npm安装的yarn npm…...

【ETCD】【源码阅读】stepWithWaitOption方法解析

在分布式系统中,ETCD 作为一个强一致性、高可用的 key-value 存储系统,广泛应用于服务发现、配置管理等场景。ETCD 在内部采用了 Raft 协议来保证集群的一致性,而日志预提案(log proposal)是 Raft 协议中至关重要的一部…...

redis 怎么样查看list

在 Redis 中,可以通过以下方法查看列表的内容或属性: 1. 查看列表中的所有元素 使用 LRANGE 命令: LRANGE key start endkey 是列表的名称。start 是起始索引,0 表示第一个元素。end 是结束索引,-1 表示最后一个元素…...

E: 无法获取 dpkg 前端锁 (/var/lib/dpkg/lock-frontend),是否有其他进程正占用它?

我们在使用Ubuntu系统时经常性使用sudo apt install命令安装所需要的软件库,偶尔会出现如下问题: E: 无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用) E: 无法获取 dpkg 前端锁 (/var/lib/dpkg/lock-frontend),是否有其…...

创建型设计模式

一、设计模式介绍 1.设计模式是什么 设计模式是指在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案; 2.设计模式怎么来的? 满足设计原则后,慢慢迭代出来的。 3.设…...

仿iOS日历、飞书日历、Google日历的日模式

仿iOS日历、飞书日历、Google日历的日模式,24H内事件可自由上下拖动、自由拉伸。 以下是效果图: 具体实现比较简单,代码如下: import android.content.Context; import android.graphics.Canvas; import android.graphics.Color;…...

vuedraggable

官方文档:https://www.npmjs.com/package/vuedraggable 中文文档:http://www.itxst.com/vue-draggable/tutorial.html 案例下载地址: https://github.com/SortableJS/Vue.Draggable.git vuedraggablehttps://sortablejs.github.io/Vue.Dr…...

新手从事直播软件源码开发搭建经验与技巧

如果从YY或六间房的PC秀场直播间系统软件算起,直播软件已经在国内风云了至少10年了,站在用户角度提到直播系统大家基本都知道核心功能有开直播刷礼物等,那么如果站在直播软件源码开发搭建的技术角度去看呢?是不是要从需求调研分析…...

相机不动,机构动作----Hands Eyes

最近在研究 手眼标定,发现大家都需付费,搞啥子,说好的开源。。。 以相机在上固定不动,机械手为 EPSON_Robot 为例,详细的一步一步实例操作指引 EPSON_Robot 的192.168.0.1 2004 Server 详细操作步骤 1. 启动程序 运…...

Scala的导入

//导入 //(1) 创建包:在src上右键,新建软件包 //(2)填写包名:小写 //(3)在包上右键,创建类。自动加入包名 //(4)导入。import 包名.类名 //导入多个类 //import jh.yuanlixueyuan.bigdata.scala03.{A,B,C} //导入包下的所有的类 /…...

vue2中父子组件传值案例总结

在 Vue 2 中&#xff0c;父子组件之间的传值是通过 props 和事件来实现的。下面是详细的解释和总结&#xff1a; 1. 父组件向子组件传值 父组件可以通过 props 向子组件传递数据。以下是一个简单的示例&#xff1a; 父组件 (Parent.vue) <template><div><h1…...

功能篇:springboot中实现文件导出

### Spring Boot 中实现文件导出功能 #### 概述 在现代Web应用程序中&#xff0c;文件导出是一个常见的需求&#xff0c;允许用户将数据以特定格式&#xff08;如CSV、Excel、PDF等&#xff09;下载到本地。本文将详细介绍如何使用Spring Boot实现文件导出功能&#xff0c;并…...

Redis客户端(Jedis、RedisTemplate、Redisson)

1. 简介 Redis作为一个当下很火热的非关系型数据库&#xff0c;Java从业人员基本都离不开对Redis的使用。在Java程序中该数据库&#xff0c;需要借助于市面上的开源客户端&#xff0c;如Jedis、Spring Data Redis、Redisson&#xff0c;它们可以作为操作Redis非关系型数据库的桥…...

Mybatis中SQL的执行过程

文章目录 Mybatis 框架SQL执行过程数据库操作映射方式SQL的执行过程- SQL解析- SQL参数映射- SQL预编译- SQL执行- 结果映射- 事务处理- 缓存处理- 日志记录与监控 扩展#与$的区别- $ 符号- # 符号总结示例 Mybatis SQL分类- 动态 SQL- 静态 SQL静态SQL和动态SQL选择${}、#{}与…...

【数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 测试说明 我的通关代码: 测试结果&#xff1a; 任务描述 本关任务&#xff1a;编写一个程序实现顺序栈的基本运算。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 初始化栈、销毁栈、判断栈是否为空、进栈、出栈、取…...

【论文阅读】PRIS: Practical robust invertible network for image steganography

内容简介 论文标题&#xff1a;PRIS: Practical robust invertible network for image steganography 作者&#xff1a;Hang Yang, Yitian Xu∗, Xuhua Liu∗, Xiaodong Ma∗ 发表时间&#xff1a;2024年4月11日 Engineering Applications of Artificial Intelligence 关键…...

在Linux桌面系统普及化方面的一些建议

在推动Linux桌面系统普及化的过程中&#xff0c;可以考虑以下几个方案和策略&#xff1a; 用户友好性改进&#xff1a; 界面设计&#xff1a;提升用户界面的美观性和易用性&#xff0c;使其更接近或超越主流操作系统的用户体验。软件兼容性&#xff1a;确保常用软件&#xff08…...

LLM - 多模态大模型的开源评估工具 VLMEvalKit 部署与测试 教程

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/144353087 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 VLMEva…...

数据结构(Queue队列)

前言&#xff1a; 在计算机科学中&#xff0c;数据结构是构建高效算法和程序的基础&#xff0c;而队列&#xff08;Queue&#xff09;作为一种经典的线性数据结构&#xff0c;具有重要的地位。与栈&#xff08;Stack&#xff09;不同&#xff0c;队列遵循“先进先出”&#xf…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解

一、前言 在HarmonyOS 5的应用开发模型中&#xff0c;featureAbility是旧版FA模型&#xff08;Feature Ability&#xff09;的用法&#xff0c;Stage模型已采用全新的应用架构&#xff0c;推荐使用组件化的上下文获取方式&#xff0c;而非依赖featureAbility。 FA大概是API7之…...