IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> 区块链智能合约(Soilidtiy)攻击--已知攻击类型 -> 正文阅读

[区块链]区块链智能合约(Soilidtiy)攻击--已知攻击类型

一.Reentrancy重入攻击

调用外部合约的主要危险之一是它们可以接管控制流,并对调用函数不期望的数据进行更改。此类错误可以有多种形式,导致 DAO 崩溃的两个主要错误都是此类错误

1.单个函数的可重入性

错误例子:

要注意的这个错误的第一个版本涉及在函数的第一次调用完成之前可以重复调用的函数。这可能会导致函数的不同调用以破坏性的方式进行交互。

// INSECUREmapping?(address?=> uint) private?userBalances;

function?withdrawBalance() public?{

???uint?amountToWithdraw = userBalances[msg.sender];

????(bool?success, ) = msg.sender.call.value(amountToWithdraw)(""); // At this point, the caller's code is executed, and can call withdrawBalance again

????require(success);

????userBalances[msg.sender] = 0;}

由于直到函数结束时用户的余额才设置为 0,因此第二次(以及以后的)调用仍然会成功,并且会一遍又一遍地提取余额。?

更改后的例子:

解决办法:在给出的示例中,防止这种攻击的最佳方法是确保在完成所有需要执行的内部工作之前不要调用外部函数???

mapping?(address?=> uint) private?userBalances;

function?withdrawBalance() public?{

????uint?amountToWithdraw = userBalances[msg.sender];

????userBalances[msg.sender] = 0;

????(bool?success, ) = msg.sender.call.value(amountToWithdraw)(""); // The user's balance is already 0, so future invocations won't withdraw anything

require(success);

}

请注意,如果您有另一个调用 的函数withdrawBalance(),它可能会受到相同的攻击,因此您必须将调用不受信任的合约的任何函数视为自身不受信任。有关潜在解决方案的进一步讨论,请参见下文。

?2.Cross-function Reentrancy跨功能重入

攻击者也可以使用共享相同状态的两个不同函数进行类似的攻击

// INSECURE

mapping?(address?=> uint) private?userBalances;

function?transfer(address?to, uint?amount) {

????if?(userBalances[msg.sender] >= amount) {

???????userBalances[to] += amount;

???????userBalances[msg.sender] -= amount;

????}}

function?withdrawBalance() public?{

????uint?amountToWithdraw = userBalances[msg.sender];

????(bool?success, ) = msg.sender.call.value(amountToWithdraw)(""); // At this point, the caller's code is executed, and can call transfer()

????require(success);

????userBalances[msg.sender] = 0;}

在这种情况下,攻击者transfer()会在外部调用中执行其代码时调用withdrawBalance。由于他们的余额尚未设置为 0,因此即使他们已经收到提款,他们也可以转移代币。该漏洞也被用于DAO攻击。

相同的解决方案将起作用,但有相同的警告。还要注意,在这个例子中,两个函数都是同一个合约的一部分。但是,如果多个合约共享状态,则相同的错误可能会发生在多个合约中。

3.重入解决方案中的陷阱

由于重入可能发生在多个函数甚至多个合约中,任何旨在防止单个函数重入的解决方案都是不够的。

相反,我们建议先完成所有内部工作(即状态更改),然后再调用外部函数。如果仔细遵循此规则,则可以避免由于可重入而导致的漏洞。但是,不仅要避免过早调用外部函数,还要避免调用调用外部函数的函数。例如,以下是不安全的

// INSECURE

mapping?(address?=> uint) private?userBalances;

mapping?(address?=> bool) private?claimedBonus;

mapping?(address?=> uint) private?rewardsForA;

function?withdrawReward(address?recipient) public?{

????uint?amountToWithdraw = rewardsForA[recipient];

????rewardsForA[recipient] = 0;

????(bool?success, ) = recipient.call.value(amountToWithdraw)("");

require(success);

}

function?getFirstWithdrawalBonus(address?recipient) public?{

????require(!claimedBonus[recipient]); // Each recipient should only be able to claim the bonus once

????rewardsForA[recipient] += 100;

????withdrawReward(recipient); // At this point, the caller will be able to execute getFirstWithdrawalBonus again.

claimedBonus[recipient] = true;

}

即使getFirstWithdrawalBonus()不直接调用外部合约,调用withdrawReward()也足以使其容易受到重入的影响。因此,您需要将其withdrawReward()视为不受信任。

mapping?(address?=> uint) private?userBalances;

mapping?(address?=> bool) private?claimedBonus;

mapping?(address?=> uint) private?rewardsForA;

function?untrustedWithdrawReward(address?recipient) public?{

????uint?amountToWithdraw = rewardsForA[recipient];

????rewardsForA[recipient] = 0;

????(bool?success, ) = recipient.call.value(amountToWithdraw)("");

????require(success);}

function?untrustedGetFirstWithdrawalBonus(address?recipient) public?{

????require(!claimedBonus[recipient]); // Each recipient should only be able to claim the bonus once



????claimedBonus[recipient] = true;

????rewardsForA[recipient] += 100;

????untrustedWithdrawReward(recipient); // claimedBonus has been set to true, so reentry is impossible}

除了无法重新进入的修复之外,不受信任的功能已被标记为。在各个层面同样的模式重复:因为untrustedGetFirstWithdrawalBonus()?calls?untrustedWithdrawReward(),要求外部合同,你也必须把untrustedGetFirstWithdrawalBonus()为不安全。

通常建议的另一个解决方案是互斥锁。这允许您“锁定”某些状态,因此它只能由锁的所有者更改。一个简单的例子可能如下所示:

// Note: This is a rudimentary example, and mutexes are particularly useful where there is substantial logic and/or shared state

mapping?(address?=> uint) private?balances;

bool?private?lockBalances;

function?deposit() payable?public?returns?(bool) {

????require(!lockBalances);

????lockBalances = true;

????balances[msg.sender] += msg.value;

????lockBalances = false;

????return?true;}

function?withdraw(uint?amount) payable?public?returns?(bool) {

????require(!lockBalances && amount > 0?&& balances[msg.sender] >= amount);

????lockBalances = true;



????(bool?success, ) = msg.sender.call(amount)("");



????if?(success) { // Normally insecure, but the mutex saves it

??????balances[msg.sender] -= amount;

????}



????lockBalances = false;

????return?true;}

如果用户withdraw()在第一次调用结束前再次尝试调用,锁将阻止它产生任何影响。这可能是一种有效的模式,但是当您有多个需要合作的合约时,它会变得棘手。以下是不安全的

// INSECURE

contract?StateHolder {

????uint?private?n;

????address?private?lockHolder;



????function?getLock() {

????????require(lockHolder == address(0));

????????lockHolder = msg.sender;

????}



????function?releaseLock() {

????????require(msg.sender?== lockHolder);

????????lockHolder = address(0);

????}



????function?set(uint?newState) {

????????require(msg.sender?== lockHolder);

????????n = newState;

????}}

攻击者可以调用getLock(),然后永远不会调用releaseLock()。如果他们这样做,那么合约将被永久锁定,并且无法进行进一步的更改。如果您使用互斥锁来防止重入,您将需要仔细确保没有任何方法可以声明锁并且永不释放。(在使用互斥锁编程时还有其他潜在的危险,例如死锁和活锁。如果您决定走这条路,您应该查阅已经写在互斥锁上的大量文献。)

以上是涉及攻击者在单个事务中执行恶意代码的可重入示例。以下是区块链固有的一种不同类型的攻击:交易本身(例如,在一个区块内)的顺序很容易受到操纵这一事实。

二.Front-Running(抢先交易攻击)

由于所有交易在执行之前都在内存池中短暂可见,因此网络的观察者可以在将其包含在块中之前看到并对其做出反应。如何利用这一点的一个例子是去中心化交易所,在那里可以看到购买订单交易,并且可以在包含第一笔交易之前广播和执行第二笔订单。防止这种情况很困难,因为这将归结为具体的合同本身

领先,最初是为传统金融市场创造的,是为了赢家的利益而整理混乱的竞赛。在金融市场中,信息流动催生了中介机构,它们可以通过第一个知道某些信息并对某些信息做出反应来获利。这些攻击主要发生在股票市场交易和早期域名注册中,例如 whois 网关

分类?

通过定义分类法并将每个组与另一个组区分开来,我们可以更轻松地讨论问题并为每个组找到解决方案。

我们定义了以下类别的抢先攻击:

  1. Displacement移位

在第一种类型的攻击中,置换攻击,Alice(用户)的函数调用在 Mallory(对手)运行她的函数之后运行并不重要。爱丽丝的可以成为孤儿或运行没有任何有意义的影响。置换的例子包括: * Alice 试图注册一个域名,Mallory 首先注册它;* Alice 试图提交一个 bug 以获得赏金,而 Mallory 窃取它并首先提交它;* 爱丽丝试图在拍卖中出价,而马洛里抄袭。

这种攻击通常通过增加gasPrice高于网络平均值的倍数来执行,通常乘数为 10 或更多。

  1. Insertion插入

对于这种类型的攻击,原始函数调用在她的交易之后运行对对手来说很重要。在插入攻击中,Mallory 运行她的函数后,合约的状态发生了变化,她需要 Alice 的原始函数在这个修改后的状态上运行。例如,如果 Alice 以高于最佳报价的价格对区块链资产下订单,Mallory 将插入两笔交易:她将以最佳报价购买,然后以 Alice 稍高的购买价格出售相同的资产.?如果 Alice 的交易随后被执行,Mallory 将在无需持有资产的情况下从差价中获利。

与置换攻击一样,这通常是通过在 gas 价格拍卖中出价高于 Alice 的交易来完成的。

  1. Suppression抑制

在抑制攻击中,也就是Block Stuffing攻击,在 Mallory 运行她的函数后,她试图延迟 Alice 运行她的函数。

“Fomo3d”游戏的第一个获胜者和其他一些链上黑客就是这种情况。攻击者发送多个交易具有高gasPricegasLimit?定制智能合同是断言(或使用其他方式),以消耗所有的气体,并填补了块的gasLimit

这些攻击中的每一种都有两种变体,非对称和批量。

在某些情况下,Alice 和 Mallory 正在执行不同的操作。例如,Alice 试图取消一个要约,而 Mallory 则试图先完成它。我们称之为不对称位移。在其他情况下,Mallory 试图运行大量功能:例如 Alice 和其他人试图购买由一家公司在区块链上提供的一组有限的股票。我们称之为大容量位移。

三.时间戳依赖()

请注意,矿工可以操纵区块的时间戳,应考虑所有直接和间接使用时间戳的情况。

四.整数上溢和下溢

考虑一个简单的代币转移:

mapping?(address?=> uint256) public?balanceOf;

// INSECUREfunction?transfer(address?_to, uint256?_value) {

????/* Check if sender has balance */

????require(balanceOf[msg.sender] >= _value);

????/* Add and subtract new balances */

????balanceOf[msg.sender] -= _value;

????balanceOf[_to] += _value;}

// SECUREfunction?transfer(address?_to, uint256?_value) {

????/* Check if sender has balance and for overflows */

????require(balanceOf[msg.sender] >= _value && balanceOf[_to] + _value >= balanceOf[_to]);



????/* Add and subtract new balances */

????balanceOf[msg.sender] -= _value;

????balanceOf[_to] += _value;}

如果余额达到最大 uint 值 (2^256),它将循环回零以检查条件。这可能相关也可能不相关,具体取决于实现。想一想这个uint值有没有机会逼近这么大的数字。考虑uint变量如何更改状态,以及谁有权进行此类更改。如果任何用户都可以调用更新uint值的函数,则更容易受到攻击。如果只有管理员有权更改变量的状态,那么您可能是安全的。如果用户一次只能增加 1,你可能也是安全的,因为没有可行的方法来达到这个限制。

下溢也是如此。如果 uint 小于零,它将导致下溢并设置为其最大值。

小心较小的数据类型,如 uint8、uint16、uint24...等:它们更容易达到最大值。

  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2021-12-28 22:59:10  更:2021-12-28 22:59:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:24:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码