Rust智能合约DoS漏洞分析:循环遍历、跨合约依赖与权限设计

robot
摘要生成中

Rust智能合约中的DoS攻击漏洞分析

DoS (Denial of Service)攻击会导致智能合约在一段时间内甚至永久无法被正常使用。主要原因包括:

  1. 合约逻辑中存在缺陷。如某些public函数实现未考虑计算复杂度,导致Gas消耗超出限制。

  2. 跨合约调用时对外部合约执行状态的依赖。外部合约执行不可靠可能导致本合约被阻塞。

  3. 人为因素,如合约所有者丢失私钥,导致重要的系统状态无法及时更新。

下面通过具体例子分析DoS攻击漏洞。

1. 循环遍历可被外部更改的大型数据结构

以下是一个为注册用户"分红"的简单合约:

rust #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub registered: Vec, pub accounts: UnorderedMap<accountid, balance="">, }

pub fn register_account(&mut self) { if self.accounts.insert(&env::predecessor_account_id(), &0).is_some() { env::panic("The account is already registered".to_string().as_bytes()); } else { self.registered.push(env::predecessor_account_id()); } log!("Registered account {}", env::predecessor_account_id()); }

pub fn distribute_token(&mut self, amount: u128) { assert_eq!(env::predecessor_account_id(), DISTRIBUTOR, "ERR_NOT_ALLOWED");

for cur_account in self.registered.iter() {
    let balance = self.accounts.get(&cur_account).expect("ERR_GET");
    self.accounts.insert(&cur_account, &balance.checked_add(amount).expect("ERR_ADD"));
    log!("Try distribute to account {}", &cur_account);
    
    ext_ft_token::ft_transfer(
        cur_account.clone(),
        amount,
        &FTTOKEN,
        0,
        GAS_FOR_SINGLE_CALL
    );
}

}

该合约状态数据self.registered大小无限制,可被恶意用户操控使之过大。导致distribute_token执行时Gas消耗超出限制而失败。

推荐改用提现模式:合约方先记账,用户通过withdraw函数自行取回奖励。合约只需维护单一用户的奖励数额。

2. 跨合约状态依赖导致合约阻塞

考虑一个"竞价"合约:

rust #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub registered: Vec, pub bid_price: UnorderedMap<accountid,balance>, pub current_leader: AccountId, pub highest_bid: u128, pub refund: bool }

pub fn bid(&mut self, sender_id: AccountId, amount: u128) -> PromiseOrValue { assert!(amount > self.highest_bid);

if self.current_leader == DEFAULT_ACCOUNT {
    self.current_leader = sender_id;
    self.highest_bid = amount;
} else {
    ext_ft_token::account_exist(
        self.current_leader.clone(),
        &FTTOKEN,
        0,
        env::prepaid_gas() - GAS_FOR_SINGLE_CALL * 4,
    ).then(ext_self::account_resolve(
        sender_id,
        amount,
        &env::current_account_id(),
        0,
        GAS_FOR_SINGLE_CALL * 3,
     ));
}

log!(
    "current_leader: {} highest_bid: {}",
    self.current_leader,
    self.highest_bid
);

PromiseOrValue::Value(0)

}

该合约逻辑依赖退回前一出价最高者代币才能更新新的最高出价。如果前者账户已注销,新的出价将被阻塞。

解决方法:考虑外部调用可能失败的情况,增加错误处理。可将无法退回的代币暂存,之后用户自行提取。

3. Owner私钥丢失

部分合约函数被设置为仅owner可执行,用于更改关键系统变量。如果owner无法履行职能(如私钥丢失),这些功能将无法使用,可能导致合约瘫痪。

解决方法:

  • 设置多个owner共同治理
  • 采用多签方案替代单一owner权限控制
  • 实现去中心化治理机制

合理的权限设计和治理机制可以有效降低单点故障风险,提高合约的鲁棒性。

</accountid,balance></accountid,>

此页面可能包含第三方内容,仅供参考(非陈述/保证),不应被视为 Gate 认可其观点表述,也不得被视为财务或专业建议。详见声明
  • 赞赏
  • 7
  • 分享
评论
0/400
MEV猎手阿福vip
· 07-17 08:49
循环遍历调用超级危险 之前亏过
回复0
BridgeNomadvip
· 07-15 16:21
上个月在 BSC 上见过这个确切的攻击向量……开发者们什么时候才能学会,摇头叹息。
查看原文回复0
熊市生存者vip
· 07-14 20:00
代码战场老兵回归,战损得亏有仓位管理在
回复0
BearMarketSurvivorvip
· 07-14 19:57
私钥丢了咋整 慌得不行
回复0
FlatlineTradervip
· 07-14 19:56
合约设计这么烂还发出来
回复0
元宇宙资深流浪汉vip
· 07-14 19:54
这个BUG危险度到有点高
回复0
Hodl老司机vip
· 07-14 19:34
一看就是老手翻车后的血泪教训...
回复0
交易,随时随地
qrCode
扫码下载 Gate APP
社群列表
简体中文
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)