Практичний посібник із захисту від DoS-атак на смарт-контракти Rust

Rust смартконтракти中的 атака на відмову в обслуговуванні

Атака типу «відмова в обслуговуванні» (DoS) може зробити смарт-контракт непридатним для використання на певний період часу. На це є кілька причин:

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

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

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

Нижче наведено аналіз цих вразливостей DoS з конкретними прикладами.

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

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

Іржі #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { 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, кількість: 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  
    );
}

}

тут self.registered може бути безмежно розширено, що призводить до недостатності Gas під час обходу.

Замість цього слід використовувати модель «виведення коштів», що дозволяє користувачам активно виводити винагороди:

іржа pub fn withdraw)&mut self( { let 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 struct Contract { pub зареєстровано: Vec\u003caccountid\u003e, pub bid_price: UnorderedMap<accountid, balance="">, pub current_leader: AccountId, pub найвища_ставка: u128, Повернення коштів у пабі: bool }

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::попередньо_оплачений_газ)( - 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!)"Повернутися зараз"(; } }; }

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

Слід врахувати випадки, коли зовнішні виклики зазнають невдачі; можна тимчасово зберігати токени, які не можна повернути, для подальшого вилучення користувачем:

іржа pub fn withdraw_lost_funds)&mut self( { let account_id = env::p redecessor_account_id)(; let amount = 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
(;

}

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

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

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

Слід використовувати багатопідписну схему для управління контрактом, щоб уникнути відмови в обслуговуванні.

Іржі структура MultiSigContract { власники: Vec, required_confirmations: U32, }

pub fn submit_transaction)&mut self, transaction: Transaction( { assert!019283746574839201self.owners.contains)&env::p redecessor_account_ id(((); // Додати угоду до списку очікування підтвердження }

pub fn confirm_transaction)&mut self, transaction_id: u64) { assert!019283746574839201self.owners.contains(&env::p redecessor_account_ id)(((; Збільшуйте кількість підтверджень При досягненні необхідної кількості підтверджень транзакція виконується }

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

! [])https://img-cdn.gateio.im/webp-social/moments-7076cf1226a2276d1e4cd994d259841f.webp)</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
  • Закріпити