Rustスマートコントラクトの安全性: DoS攻撃を防ぐための3つの重要な戦略

Rustスマートコントラクト安全:防御サービス拒否攻撃

サービス拒否攻撃(DoS)攻撃は、スマートコントラクトが一定期間正常に使用できなくなったり、さらには永久に機能不全に陥る原因となります。主な原因には次のようなものがあります:

  1. 合約ロジックに計算の複雑度が高すぎる欠陥が存在し、Gas消費が制限を超えています。

  2. クロスコントラクト呼び出し時の外部コントラクトの実行状態への依存は、外部コントラクトによってブロックされる可能性があります。

  3. コントラクトの所有者が秘密鍵を失い、重要な特権関数を実行できません。

以下に具体例を用いて分析します。

1. 外部から操作可能な大規模データ構造の走査を避ける

以下は簡単な"分配"スマートコントラクトで、DoSリスクがあります:

さび #[near_bindgen] #[derive(BorshDeserialize、BorshSerialize)] pub struct コントラクト { パブ登録:Vec、 パブアカウント: UnorderedMap<accountid, balance="">, }

pub fn register_account(&mut self) { self.accounts.insert(&env::p redecessor_account_id()、&0).is_の場合 some() { env::panic("アカウントはすでに登録されています".to_string().as_bytes()); } else { self.registered.push(env::p redecessor_account_id()); } log!("登録済みアカウント {}", env::p redecessor_account_id()); }

pub fn distribute_token(&mut self, amount: u128) { assert_eq!(env::p redecessor_account_id(), ディストリビューター, "ERR_NOT_ALLOWED");

for cur_account in self.registered.iter() {
    バランス= self.accounts.get(&cur_account).expect("ERR_GET");
    self.accounts.insert(&cur_account, &balance.checked_add(amount).expect("ERR_ADD" ));
    log!("アカウント {} に配布を試みる", &cur_account);
    
    ext_ft_token::ft_transfer(
        cur_account.clone()、
        量
        &FTTOKENや
        0,
        GAS_FOR_SINGLE_CALL
    );
}

}

この契約の問題は、registered配列のサイズに制限がなく、悪意のあるユーザーによって過大に操作される可能性があるため、distribute_token関数のGas消費が制限を超えることです。

推奨される解決策は「出金」モードを採用することです:

サビ pub fn distribute_token(&mut self, amount: u128) { assert_eq!(env::p redecessor_account_id(), ディストリビューター, "ERR_NOT_ALLOWED");

self.registered.iter() {
    バランス= self.accounts.get(&account).unwrap();
    self.accounts.insert(&account, &(balance + amount));
}

}

pub fn withdraw(&mut self) { アカウント= env::p redecessor_account_id(); let amount = self.accounts.get(&account).unwrap(); self.accounts.insert(&アカウント、&0);

ext_ft_token::ft_transfer(account, 金額, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL);

}

!

2. コントラクト間の状態依存を避ける

以下は"入札"契約の例です:

さび #[near_bindgen] #[derive(BorshDeserialize、BorshSerialize)] pub struct コントラクト { パブ登録:Vec、 pub bid_price: UnorderedMap<accountid,balance>, 公開current_leader: AccountId, パブhighest_bid:U128、 }

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

if self.current_leader == DEFAULT_ACCOUNT {
    self.current_leader = sender_id;
    self.highest_bid = 金額;
} else {
    ext_ft_token::account_exist(
        self.current_leader.clone()、
        &FTTOKENや
        0,
        env::p repaid_gas() - GAS_FOR_SINGLE_CALL * 4、
    ).then(ext_self::account_resolve(
        sender_id、
        量
        &env::current_account_id()、
        0,
        GAS_FOR_SINGLE_CALL*3、
    ));
}

PromiseOrValue::Value(0)

}

#[private] pub fn account_resolve(&mut self, sender_id: AccountId, amount: u128) { 一致 env::p romise_result(0) { PromiseResult::Successful(_) => { ext_ft_token::ft_transfer( self.current_leader.clone()、 self.highest_bid、 &FTTOKENや 0, GAS_FOR_SINGLE_CALL2、 ); self.current_leader = sender_id; self.highest_bid = 金額; } PromiseResult::失敗 => { ext_ft_token::ft_transfer( sender_id.clone()、 量 &FTTOKENや 0, GAS_FOR_SINGLE_CALL2、 ); log!("今すぐ戻る"); } PromiseResult::NotReady => 到達不能!() }; }

この契約の問題は、前の最高入札者がアカウントをキャンセルした場合、新しい入札者が状態を正常に更新できなくなることです。

解決策は合理的なエラーハンドリングを実装することです。例えば、返却できないトークンを一時保管し、後でユーザーが自分で引き出すようにします。

さび pub struct コントラクト { // ... pub lost_found: UnorderedMap<accountid, balance="">, }

pub fn account_resolve(&mut self, sender_id: AccountId, amount: u128) { 一致 env::p romise_result(0) { PromiseResult::Successful(_) => { // 通常の返金ロジック } PromiseResult::失敗 => { // 返金できないトークンを一時保管 let lost_amount = self.lost_found.get(&self.current_leader).unwrap_or(0); self.lost_found.insert(&self.current_leader, &(lost_amount + self.highest_bid));

        // ステータスを更新
        self.current_leader = sender_id;
        self.highest_bid = 金額;
    }
    PromiseResult::NotReady => 到達不能!()
}

}

pub fn withdraw_lost_found(&mut self) { アカウント= env::p redecessor_account_id(); let amount = self.lost_found.get(&account).unwrap_or(0); if 金額 > 0 { self.lost_found.insert(&account, &0); ext_ft_token::ft_transfer(account, 金額, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL); } }

3. 単一障害点の回避

コントラクト所有者の秘密鍵が失われると、重要な特権機能が使用できなくなります。解決策はマルチシグネチャメカニズムを採用することです。

サビ pub struct コントラクト { パブのオーナー:ベック、 パブrequired_confirmations:U64、 パブトランザクション:Vec、 }

pub fn propose_transaction(&mut self, transaction: Transaction) { assert!(self.owners.contains(&env::p redecessor_account_id()), "いいえ 所有者"); self.transactions.push(トランザクション); }

pub fn confirm_transaction(&mut self, transaction_id: u64) { assert!(self.owners.contains(&env::p redecessor_account_id()), "いいえ 所有者");

let transaction = &mut self.transactions[transaction_id as usize];
transaction.confirmations += 1;

if transaction.confirmations >= self.required_confirmations {
    self.execute_transaction(transaction_id);
}

}

fn execute_transaction(&mut self, transaction_id: u64) { let transaction = self.transactions.remove(transaction_id as usize); // 取引ロジックを実行 }

マルチシグネチャ機構を通じて、単一の所有者の秘密鍵の喪失による契約の麻痺を回避し、契約の非中央集権性と安全性を向上させることができます。

! </accountid,></accountid,balance></accountid,>

原文表示
このページには第三者のコンテンツが含まれている場合があり、情報提供のみを目的としております(表明・保証をするものではありません)。Gateによる見解の支持や、金融・専門的な助言とみなされるべきものではありません。詳細については免責事項をご覧ください。
  • 報酬
  • 5
  • 共有
コメント
0/400
GasFeeNightmarevip
· 18時間前
それは大きなガスプレーヤーになるに値します
原文表示返信0
PretendingToReadDocsvip
· 18時間前
DoSは避けられないので、他に何の安全性を議論できますか?
原文表示返信0
HashRatePhilosophervip
· 19時間前
rust軍が来たぞ、敵は震え上がれ
原文表示返信0
TestnetFreeloadervip
· 19時間前
防dosあなたはこの罠理論にいるのですか
原文表示返信0
MevShadowrangervip
· 19時間前
ガス代が爆上がりでまいった
原文表示返信0
  • ピン
いつでもどこでも暗号資産取引
qrCode
スキャンしてGateアプリをダウンロード
コミュニティ
日本語
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)