Посібник з практичної протидії атакам DoS на смартконтракти Rust

Щоденник розвитку смартконтрактів на Rust: запобігання атакам на відмову в обслуговуванні

атака на відмову в обслуговуванні(DoS) може призвести до того, що смартконтракти не зможуть нормально використовуватися протягом певного часу або навіть назавжди. Загальні причини включають:

  1. Проблема обчислювальної складності в логіці контракту, що призводить до перевищення обмеження споживання Gas.

  2. Під час міжконтрактного виклику неналежна залежність від стану зовнішнього контракту призводить до блокування цього контракту.

  3. Втрата приватного ключа власника контракту призводить до неможливості виклику привілейованих функцій та оновлення важливого стану системи.

Нижче наведено кілька конкретних прикладів для аналізу вразливостей атаки на відмову в обслуговуванні (DoS) та їхніх рішень.

1. Циклічний перебір великих структур даних, які можуть бути змінені зовні

Наступний є простим "договором про дивіденди", існує ризик атаки на відмову в обслуговуванні:

іржа #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub зареєстровано: Vec\u003caccountid\u003e, облікові записи pub: UnorderedMap<accountid, balance="">, }

impl Контракт { 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::predecessor_account_id()); }

pub fn distribute_token(&mut self, кількість: u128) {
    assert_eq!(env::p redecessor_account_id(), ДИСТРИБ'ЮТОР, "ERR_NOT_ALLOWED");
    
    для cur_account в self.registered.iter() {
        let balance = self.accounts.get(&cur_account).expect("ERR_GET");
        self.accounts.insert019283746574839201&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.

Рекомендоване рішення:

  1. Обмежити розмір масиву registered.

  2. Використання режиму "виведення коштів", що дозволяє користувачам самостійно отримувати винагороди, а не активного розподілу з боку смартконтракту.

! [])https://img-cdn.gateio.im/webp-social/moments-b7bbfcf4423b1cf19db56a3af95a7486.webp(

2. Залежність стану між смартконтрактами призводить до блокування контракту

Наступний приклад "аукціонного" смартконтракту:

іржа #[near_bindgen] #[derive)BorshDeserialize, BorshSerialize(] pub struct Контракт { pub зареєстровані: Vec, pub bid_price: UnorderedMap<accountid,balance>, pub current_leader: AccountId, highest_bid пабу: U128, Повернення коштів у пабі: bool }

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(
}

#)
pub fn account_resolve[private]&mut self, sender_id: AccountId, amount: u128( {
    match env::p romise_result)0( {
        PromiseResult::NotReady => недосяжний!)(,
        PromiseResult::Успішний)_( => {
            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!)"Повернутися зараз"(;
        }
    };
}

}

Проблема в тому, що оновлення стану контракту залежить від викликів зовнішніх контрактів. Якщо обліковий запис попереднього найвищого учасника торгів був анульований, наступні учасники торгів не зможуть оновити стан.

Рекомендоване рішення:

Розгляньте можливість того, що зовнішні виклики можуть завершитися невдачею, реалізуйте розумний механізм обробки помилок. Наприклад, тимчасово зберігайте токени, які не можна повернути, у контракті, а пізніше дозволяйте користувачам самостійно їх витягувати.

3. Втрата приватного ключа власника

Багато контрактів мають функції привілеїв, які може виконувати лише власник. Якщо приватний ключ власника буде втрачено, ці функції не зможуть бути викликані, що може призвести до некоректної роботи контракту.

Рекомендоване рішення:

  1. Налаштуйте кількох власників контракту для спільного управління.

  2. Використання механізму мультипідпису для заміни контролю одного власника.

  3. Реалізувати децентралізований механізм управління контрактами.

Завдяки вищезазначеним заходам можна ефективно знизити ризик атаки на відмову в обслуговуванні в смартконтрактах, підвищивши безпеку та надійність контракту.

! [])https://img-cdn.gateio.im/webp-social/moments-7076cf1226a2276d1e4cd994d259841f.webp(</accountid,balance></accountid,>

Переглянути оригінал
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
  • Нагородити
  • 8
  • Поділіться
Прокоментувати
0/400
MEVHunterWangvip
· 6год тому
Гратися з контрактом ще не означає, що ти не можеш контролювати ситуацію.
Переглянути оригіналвідповісти на0
ProofOfNothingvip
· 10год тому
Знову формалізм і порожні розмови
Переглянути оригіналвідповісти на0
LuckyHashValuevip
· 13год тому
Атака не була зупинена, знову буде падіння до нуля.
Переглянути оригіналвідповісти на0
ColdWalletGuardianvip
· 13год тому
Блокчейн вхідний комплект знань
Переглянути оригіналвідповісти на0
SelfSovereignStevevip
· 13год тому
Закритий ключ втрачене, це буде жахливо.
Переглянути оригіналвідповісти на0
StableBoivip
· 13год тому
Цей контракт дійсно має деякі ризики, його стабільність не дуже хороша.
Переглянути оригіналвідповісти на0
Ser_This_Is_A_Casinovip
· 13год тому
Ах~Rust справді важко, краще розглянути Solidity
Переглянути оригіналвідповісти на0
GasFeeThundervip
· 13год тому
газ їсть занадто багато, що робити? Рано чи пізно контракт буде вичавлений до сухого.
Переглянути оригіналвідповісти на0
  • Закріпити