Анализ уязвимости DoS-атак смарт-контрактов Rust и решения

Атака типа «отказ в обслуживании» в смарт-контрактах Rust

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

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

  2. В межконтрактных вызовах выполнение контракта зависит от состояния внешнего контракта и может быть заблокировано внешним контрактом.

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

Ниже приведен анализ уязвимости DoS-атаки в смарт-контрактах на конкретных примерах.

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

Вот простой смарт-контракт для распределения дивидендов зарегистрированным пользователям:

ржавчина #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Контракт { pub зарегистрированные: Vec\u003caccountid\u003e, аккаунты пабов: 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()); } иначе { self.registered.push(env::p redecessor_account_id()); } log!("Регистрация аккаунта {}", env::предшествующий_id_аккаунта()); }

pub fn distribute_token(&mut self, сумма: u128) {
    assert_eq!(env::predecessor_account_id(), DISTRIBUTOR, "Нет прав для выполнения операции");
    для аккаунта в self.registered.iter() {
        let balance = self.accounts.get(&account).expect("Потерпи неудачу");
        self.accounts.insert(&account, &balance.checked_add(amount).expect( "Дополнительное переполнение" )); 
        log!("Попытка распределить на счет {}", &account);
        ext_ft_token::ft_transfer(
            аккаунт.клон(),
            сумма,
            &FTTOKEN,
            0,
            GAS_FOR_SINGLE_CALL
        );
    }
}

}

Проблема контракта заключается в том, что размер массива registered не ограничен, что позволяет злоумышленникам манипулировать им и делать его слишком большим, что приводит к чрезмерным расходам газа в функции distribute_token.

Рекомендуемые решения:

Реконструкция контракта с использованием режима вывода средств. Позвольте пользователю самостоятельно вызывать функцию вывода средств для получения вознаграждения, контракту нужно лишь записывать сумму вознаграждения, которую пользователь может вывести.

!

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

Рассмотрим контракт на торги:

ржавчина #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Контракт { pub зарегистрированные: Vec, паб 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 { assert!(amount > self.highest_bid); если self.current_leader == DEFAULT_ACCOUNT { self.current_leader = sender_id; self.highest_bid = сумма; } иначе { ext_ft_token::account_exist( self.current_leader.клон(), &FTTOKEN, 0, env::предоплаченный_газ() - ГАЗ_ДЛЯ_ОДИНОЧНОГО_ВЫЗОВА * 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) {
    match env::p romise_result(0) {
        PromiseResult::NotReady => недостижимо!(),
        PromiseResult::Successful(_) => {
            ext_ft_token::ft_transfer(
                self.current_leader.клон(),
                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.клон(),
                сумма,
                &FTTOKEN,
                0,
                GAS_FOR_SINGLE_CALL * 2,
            );
            log!("Вернуть текущую ставку");
        }
    };
}

}

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

Способ решения:

Учитывая возможность неудачного вызова внешних смарт-контрактов, реализуйте разумную обработку ошибок. Можно временно хранить невозвратные токены в смарт-контрактах, затем разрешить пользователям самостоятельно их извлекать.

3. Потеря приватного ключа владельца контракта

Некоторые функции контракта настроены так, что только владелец может их выполнять, для изменения ключевых переменных системы. Если приватный ключ владельца будет утерян, эти функции не смогут быть вызваны, что может привести к сбою в работе контракта.

Решение:

Настройка совместного управления несколькими владельцами контрактов или использование механизма мультиподписей для замены контроля прав единственного владельца, чтобы реализовать децентрализованное управление.

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

Посмотреть Оригинал
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
  • Награда
  • 5
  • Поделиться
комментарий
0/400
LazyDevMinervip
· 21ч назад
Напишем код в следующей жизни 8
Посмотреть ОригиналОтветить0
NftPhilanthropistvip
· 21ч назад
на самом деле... *пьет чай* еще один газ-неэффективный контракт, который можно оптимизировать для социального воздействия. когда же разработчики научатся осознанным практикам кодирования, смх
Посмотреть ОригиналОтветить0
just_another_walletvip
· 21ч назад
Безопасность, ребята, это серьезный вопрос.
Посмотреть ОригиналОтветить0
NFTragedyvip
· 21ч назад
Этот вопрос, код еще не написан...
Посмотреть ОригиналОтветить0
HalfBuddhaMoneyvip
· 22ч назад
Черт, снова нужно заполнять яму, мусорный контракт
Посмотреть ОригиналОтветить0
  • Закрепить