Глибина аналізу вразливостей DoS-атак у смартконтрактах та стратегій їх запобігання

Аналіз атаки на відмову в обслуговуванні в смартконтрактах

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

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

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

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

Нижче за допомогою конкретних прикладів аналізується уразливість атаки на відмову в обслуговуванні в смартконтрактах.

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

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

іржа #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub зареєстровані: Vec\u003caccountid\u003e, облікові записи 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()); }інакше{ 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.insert(&cur_account,&balance.checked_add(amount).expect('ERR_ ДОДАТИ )); log!('Спробуйте розподілити на рахунок{}',&cur_account); ext_ft_token::ft_transfer( cur_account.clone(), сума, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL ); } }

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

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

  1. Обмежити максимальну довжину масиву self.registered
  2. Використання режиму виведення коштів, без активного обходу для розподілу винагород, а замість цього дозволити користувачам самостійно викликати функцію виведення.

!

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

Розгляньте контракт "аукціон":

іржа #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] структура Контракт { pub зареєстровані: Vec, pub bid_price: UnorderedMap<accountid,balance>, pub current_leader: AccountId, highest_bid пабу: 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::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::promise_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. Реалізація децентралізованої схеми управління контрактами

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

Переглянути оригінал
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
  • Нагородити
  • 7
  • Поділіться
Прокоментувати
0/400
consensus_whisperervip
· 07-31 14:18
І хто ж це, контракт, який і поганий, і любить грати?
Переглянути оригіналвідповісти на0
RumbleValidatorvip
· 07-30 19:13
Знову бачимо просту уразливість зациклення, перед дампом контракту необхідно провести стрес-тестування Ноди до межі.
Переглянути оригіналвідповісти на0
GasGuzzlervip
· 07-30 19:12
ГАЗові витрати відлякують! Прямо вибухає!
Переглянути оригіналвідповісти на0
BtcDailyResearchervip
· 07-30 19:10
Знову хтось попався на DoS, смішно.
Переглянути оригіналвідповісти на0
SignatureDeniedvip
· 07-30 19:05
Знову були атаковані? Хто ще наважиться зберігати закритий ключ абияк?
Переглянути оригіналвідповісти на0
DefiOldTrickstervip
· 07-30 19:02
Старий Білий ведмежий ринок зіграв свою роль, але його контракт був заблокований через втрачений закритий ключ. Хрусткий.
Переглянути оригіналвідповісти на0
RuntimeErrorvip
· 07-30 18:53
Гмм? Контракт може бути знищений через втрату Закритого ключа? Це дійсно терміново.
Переглянути оригіналвідповісти на0
  • Закріпити