دليل عملي لمواجهة هجمات DoS على العقود الذكية Rust

هجمات رفض الخدمة في عقود Rust الذكية

يمكن أن يؤدي هجوم رفض (DoS) الخدمة إلى جعل العقد الذكي غير قابل للاستخدام لفترة من الوقت. هناك عدة أسباب لذلك:

  1. يوجد عيب في منطق العقد يؤدي إلى تعقيد حسابي مرتفع، مما يؤدي إلى استهلاك الغاز بما يتجاوز الحد.

  2. عند الاستدعاء عبر العقود ، يعتمد تنفيذ العقد على حالة عقد خارجية غير موثوقة ، مما يؤدي إلى الانسداد.

  3. يفقد مالك العقد المفتاح الخاص ، مما يؤدي إلى عدم القدرة على تنفيذ الوظائف الرئيسية ذات الامتيازات.

سنحلل هذه الثغرات في هجوم حجب الخدمة من خلال أمثلة محددة.

1. استعراض هياكل البيانات الكبيرة القابلة للتغيير من قبل الخارج

以下 هو عقد "توزيع الأرباح" بسيط، هناك خطر هجوم حجب الخدمة:

صدأ #[near_bindgen] #[derive(BorshDeserialize ، BorshSerialize)] عقد بنية pub { الحانة المسجلة: Vec ، حسابات pub: 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(), DISTRIBUTOR, "ERR_NOT_ALLOWED");

ل cur_account في 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!("حاول التوزيع على الحساب {}", &cur_account);
    
    ext_ft_token::ft_transfer(
        cur_account.clone(),
        المبلغ,
        و FTTOKEN ،
        0,
        GAS_FOR_SINGLE_CALL  
    );
}

}

يمكن توسيع self.registered بلا حدود هنا، مما يؤدي إلى نقص الغاز أثناء التكرار.

يجب استخدام نموذج "السحب" بدلا من ذلك ، مما يسمح للمستخدمين بسحب المكافآت بنشاط:

صدأ pub fn withdraw(& mut self) { دع account_id = env: :p redecessor_account_id(); let amount = self.accounts.get(&account_id).expect( "بدون مكافأة");

self.accounts.insert(&account_id, &0);

ext_ft_token::ft_transfer(
    account_id،
    المبلغ، 
    و FTTOKEN ،
    0,
    GAS_FOR_SINGLE_CALL
);

}

2. الاعتماد على حالة العقد المتقاطع يؤدي إلى انسداد

以下 هو "العقود الذكية" مزايدة:

صدأ #[near_bindgen] #[derive(BorshDeserialize ، BorshSerialize)] عقد بنية pub { الحانة المسجلة: Vec ، pub bid_price: UnorderedMap<accountid, balance ="">, pub current_leader: AccountId ، حانة highest_bid: u128 ، استرداد الحانة: بول }

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

إذا كان 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 ،
    ));
}

سجل!(
    "current_leader: {} highest_bid: {}",
    الزعيم الحالي ،
    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::Failed = > { ext_ft_token::ft_transfer( sender_id.clone(), المبلغ, و FTTOKEN ، 0, GAS_FOR_SINGLE_CALL * 2 ، ); log!("العودة الآن"); } }; }

إذا تم تدمير حساب مقدم العرض السابق، فسيتم حظر العرض الجديد.

يجب مراعاة حالات فشل الاستدعاءات الخارجية، يمكن تخزين الرموز غير القابلة للإرجاع مؤقتًا، لتكون متاحة للمستخدمين لسحبها لاحقًا:

صدأ pub fn withdraw_lost_funds(&mut self) { دع account_id = env: :p redecessor_account_id(); المبلغ = self.lost_funds.get(&account_id).expect( "لا توجد أموال مفقودة");

self.lost_funds.remove(&account_id);

ext_ft_token::ft_transfer(
    account_id،
    المبلغ،
    و FTTOKEN ،
    0,
    GAS_FOR_SINGLE_CALL
);

}

!

3. فقدان المفتاح الخاص بالمالك

بعض الوظائف الرئيسية يمكن استدعاؤها فقط من قبل مالك العقد. إذا فقد المالك مفتاحه الخاص، فلن يمكن تنفيذ هذه الوظائف.

يجب استخدام خطة التوقيع المتعدد لإدارة العقود، لتجنب نقطة الفشل الفردية:

صدأ pub struct MultiSigContract { أصحابها: Vec ، required_confirmations: U32 ، }

pub fn submit_transaction(& mut self, transaction: Transaction) { تأكيد!(self.owners.contains(&env::p redecessor_account_ id())). إضافة المعاملة إلى القائمة المعلقة }

pub fn confirm_transaction(& mut self, transaction_id: u64) { تأكيد!(self.owners.contains(&env::p redecessor_account_ id())). // زيادة عدد التأكيدات إذا تم الوصول إلى العدد المطلوب من التأكيدات ، يتم تنفيذ المعاملة }

من خلال الطرق المذكورة أعلاه، يمكن التخفيف بفعالية من مخاطر هجوم حجب الخدمة في العقود الذكية.

! </accountid,>< / accountid ، >

شاهد النسخة الأصلية
قد تحتوي هذه الصفحة على محتوى من جهات خارجية، يتم تقديمه لأغراض إعلامية فقط (وليس كإقرارات/ضمانات)، ولا ينبغي اعتباره موافقة على آرائه من قبل Gate، ولا بمثابة نصيحة مالية أو مهنية. انظر إلى إخلاء المسؤولية للحصول على التفاصيل.
  • أعجبني
  • 7
  • مشاركة
تعليق
0/400
ConsensusDissentervip
· 07-19 04:59
رؤى قيمة值得收藏学习
شاهد النسخة الأصليةرد0
MEVHunterZhangvip
· 07-18 23:52
لا عجب أنه نصيحة مستندة إلى الخبرة
شاهد النسخة الأصليةرد0
PumpBeforeRugvip
· 07-18 15:28
من يدفع رسوم الغاز؟ دعنا نفهم.
شاهد النسخة الأصليةرد0
GmGnSleepervip
· 07-17 00:43
الأمان هو الأهم ولا يوجد خطأ في ذلك
شاهد النسخة الأصليةرد0
ImpermanentPhilosophervip
· 07-17 00:41
إعادة التشغيل الإجباري هي كل ما في الأمر
شاهد النسخة الأصليةرد0
GasFeePhobiavip
· 07-17 00:23
رسوم الغاز هي مشكلة كبيرة
شاهد النسخة الأصليةرد0
AllInAlicevip
· 07-17 00:21
تحسين الغاز مهم جدًا
شاهد النسخة الأصليةرد0
  • تثبيت