# Rustスマートコントラクト中的サービス拒否攻撃サービス拒否(DoS)攻撃は、スマートコントラクトが一定期間、さらには永久に正常に使用できなくなる可能性があります。主な原因は次の通りです:1. コントラクトのロジックに欠陥があり、特定の関数の計算の複雑さが高すぎて、Gas消費が制限を超える。2. コントラクト間呼び出しでは、コントラクトの実行が外部コントラクトの状態に依存しており、外部コントラクトによってブロックされる可能性があります。3. 人為的要因として、契約所有者が秘密鍵を紛失した場合、特権関数を呼び出すことができなくなります。以下は、スマートコントラクトにおけるDoS攻撃の脆弱性を分析するための具体例です。## 1. 外部から変更可能な大規模データ構造をループ遍歴する以下は、登録ユーザーに配当を提供するための簡単なスマートコントラクトです:さび#[near_bindgen]#[derive(BorshDeserialize、BorshSerialize)]pub struct コントラクト { パブ登録:Vec<accountid>、 パブアカウント: UnorderedMap<accountid, balance="">,}impl コントラクト { pub fn register_account(&mut self) { self.accounts.insert(&env::p redecessor_account_id()、&0).is_の場合 some() { env::p anic( "アカウント登録".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()、ディストリビューター、「操作を許可されていません」)。 self.registered.iter() { let balance = self.accounts.get(&account).expect("Get failed"); self.accounts.insert(&account, &balance.checked_add(amount).expect( "加算オーバーフロー" )); log!("アカウント {} への配信を試みています", &account); ext_ft_token::ft_transfer( account.clone()、 量 &FTTOKENや 0, GAS_FOR_SINGLE_CALL ); } }}この契約の問題は、registered配列のサイズに制限がなく、悪意のあるユーザーによって過大になる可能性があるため、distribute_token関数のGas消費が過度になることです。推奨ソリューション:引き出しモードで契約を再構築します。ユーザーが報酬を得るために引き出し関数を自発的に呼び出すようにし、契約はユーザーが引き出せる報酬の額を記録するだけで済みます。! [](https://img-cdn.gateio.im/social/moments-b7bbfcf4423b1cf19db56a3af95a7486)## 2. クロスコントラクト状態依存によるブロックオークション契約について考えてみましょう。さび#[near_bindgen]#[derive(BorshDeserialize、BorshSerialize)]pub struct コントラクト { パブ登録:Vec<accountid>、 pub bid_price: UnorderedMap<accountid,balance>, 公開current_leader: AccountId, パブhighest_bid:U128、 パブの払い戻し:ブール}impl コントラクト { pub fn bid(&mut self, sender_id: AccountId, amount: u128) -> PromiseOrValue<u128> { アサート!(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、 )); } ログ!( "現在の最高入札者: {} 最高入札者: {}", self.current_leader、 self.highest_bid ); PromiseOrValue::Value(0) } #[private] pub fn account_resolve(&mut self, sender_id: AccountId, amount: u128) { 一致 env::p romise_result(0) { PromiseResult::NotReady => 到達不能!() PromiseResult::Successful(_) => { ext_ft_token::ft_transfer( self.current_leader.clone()、 self.highest_bid、 &FTTOKENや 0, GAS_FOR_SINGLE_CALL*2、 ); self.current_leader = sender_id; self.highest_bid = 金額; } PromiseResult::失敗 => { ext_ft_token::ft_transfer( sender_id.clone()、 量 &FTTOKENや 0, GAS_FOR_SINGLE_CALL*2、 ); log!( "現在の入札を返す" ); } }; }}この契約の問題は、最高入札を更新するためには前の入札者のトークンを成功裏に返却しなければならないことです。前の入札者がアカウントをキャンセルした場合、契約は返金を完了できず、ブロックされます。ソリューション:外部コントラクト呼び出しが失敗する可能性を考慮し、適切なエラーハンドリングを実装します。返却できないトークンをコントラクト内に一時保管し、その後ユーザーが自主的に引き出すことを許可します。## 3. コントラクト所有者のプライベートキーの喪失一部のコントラクト関数は、重要なシステム変数を変更するために所有者のみが実行できるように設定されています。所有者の秘密鍵が失われた場合、これらの関数は呼び出すことができず、コントラクトが正常に動作しなくなる可能性があります。ソリューション:複数の契約所有者による共同ガバナンスを設定するか、単一の所有者の権限管理の代わりにマルチシグネチャメカニズムを採用して、分散型ガバナンスを実現します。! [](https://img-cdn.gateio.im/social/moments-7076cf1226a2276d1e4cd994d259841f)</u128></accountid,balance></accountid></accountid,></accountid>
RustスマートコントラクトDoS攻撃脆弱性分析と解決策
Rustスマートコントラクト中的サービス拒否攻撃
サービス拒否(DoS)攻撃は、スマートコントラクトが一定期間、さらには永久に正常に使用できなくなる可能性があります。主な原因は次の通りです:
コントラクトのロジックに欠陥があり、特定の関数の計算の複雑さが高すぎて、Gas消費が制限を超える。
コントラクト間呼び出しでは、コントラクトの実行が外部コントラクトの状態に依存しており、外部コントラクトによってブロックされる可能性があります。
人為的要因として、契約所有者が秘密鍵を紛失した場合、特権関数を呼び出すことができなくなります。
以下は、スマートコントラクトにおけるDoS攻撃の脆弱性を分析するための具体例です。
1. 外部から変更可能な大規模データ構造をループ遍歴する
以下は、登録ユーザーに配当を提供するための簡単なスマートコントラクトです:
さび #[near_bindgen] #[derive(BorshDeserialize、BorshSerialize)] pub struct コントラクト { パブ登録:Vec、 パブアカウント: UnorderedMap<accountid, balance="">, }
impl コントラクト { pub fn register_account(&mut self) { self.accounts.insert(&env::p redecessor_account_id()、&0).is_の場合 some() { env::p anic( "アカウント登録".to_string().as_bytes()); } else { self.registered.push(env::p redecessor_account_id()); } log!("アカウント登録 {}", env::p redecessor_account_id()); }
}
この契約の問題は、registered配列のサイズに制限がなく、悪意のあるユーザーによって過大になる可能性があるため、distribute_token関数のGas消費が過度になることです。
推奨ソリューション:
引き出しモードで契約を再構築します。ユーザーが報酬を得るために引き出し関数を自発的に呼び出すようにし、契約はユーザーが引き出せる報酬の額を記録するだけで済みます。
!
2. クロスコントラクト状態依存によるブロック
オークション契約について考えてみましょう。
さび #[near_bindgen] #[derive(BorshDeserialize、BorshSerialize)] pub struct コントラクト { パブ登録:Vec、 pub bid_price: UnorderedMap<accountid,balance>, 公開current_leader: AccountId, パブhighest_bid:U128、 パブの払い戻し:ブール }
impl コントラクト { 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、 )); } ログ!( "現在の最高入札者: {} 最高入札者: {}", self.current_leader、 self.highest_bid ); PromiseOrValue::Value(0) }
}
この契約の問題は、最高入札を更新するためには前の入札者のトークンを成功裏に返却しなければならないことです。前の入札者がアカウントをキャンセルした場合、契約は返金を完了できず、ブロックされます。
ソリューション:
外部コントラクト呼び出しが失敗する可能性を考慮し、適切なエラーハンドリングを実装します。返却できないトークンをコントラクト内に一時保管し、その後ユーザーが自主的に引き出すことを許可します。
3. コントラクト所有者のプライベートキーの喪失
一部のコントラクト関数は、重要なシステム変数を変更するために所有者のみが実行できるように設定されています。所有者の秘密鍵が失われた場合、これらの関数は呼び出すことができず、コントラクトが正常に動作しなくなる可能性があります。
ソリューション:
複数の契約所有者による共同ガバナンスを設定するか、単一の所有者の権限管理の代わりにマルチシグネチャメカニズムを採用して、分散型ガバナンスを実現します。
! </accountid,balance></accountid,>