Sécurité des smart contracts Rust : 3 stratégies clés pour se défendre contre les attaques DoS

Sécurité des smart contracts Rust : défense contre les attaques par déni de service

attaque par déni de service ( DoS ) peut entraîner des smart contracts qui ne peuvent pas être utilisés normalement pendant un certain temps, voire une paralysie permanente. Les principales raisons incluent :

  1. La logique du contrat présente un défaut de complexité de calcul trop élevée, entraînant une consommation de Gas dépassant la limite.

  2. La dépendance à l'état d'exécution des contrats externes lors des appels inter-contrats peut être bloquée par des contrats externes.

  3. Le propriétaire du contrat a perdu sa clé privée et ne peut pas exécuter les fonctions de privilège critiques.

Voici une analyse combinée avec des exemples concrets.

1. Évitez de parcourir de grandes structures de données pouvant être contrôlées par des tiers.

Voici un contrat de "dividende" simple, présentant un risque d'attaque par déni de service:

rouille #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contrat { pub registered: Vec\u003caccountid\u003e, pub accounts: UnorderedMap<accountid, balance="">, }

pub fn register_account(&mut self) { si self.accounts.insert(&env::predecessor_account_id(), &0).est_some() { env::panic("Le compte est déjà enregistré".to_string().as_bytes()); } else { self.registered.push(env::predecessor_account_id()); } log!("Compte enregistré {}", env::predecessor_account_id()); }

pub fn distribute_token(&mut self, amount: u128) { assert_eq!(env::predecessor_account_id(), DISTRIBUTEUR, "ERR_NOT_ALLOWED");

pour cur_account dans self.registered.iter() {
    let balance = self.accounts.get(&cur_account).expect("ERR_GET");
    self.accounts.insert(\u0026cur_account, \u0026balance.checked_add(amount).expect("ERR_ADD"));
    log!("Essayez de distribuer au compte {}", &cur_account);
    
    ext_ft_token::ft_transfer(
        cur_account.clone(),
        montant,
        &FTTOKEN,
        0,
        GAS_FOR_SINGLE_CALL
    );
}

}

Le problème de ce contrat est que la taille du tableau registered n'est pas limitée, ce qui peut être manipulé par des utilisateurs malveillants pour devenir trop grand, entraînant une consommation de Gas excessive pour la fonction distribute_token.

La solution recommandée est d'adopter le mode "retrait":

rouille pub fn distribute_token(&mut self, amount: u128) { assert_eq!(env::predecessor_account_id(), DISTRIBUTEUR, "ERR_NOT_ALLOWED");

pour compte dans self.registered.iter() {
    let balance = self.accounts.get(&account).unwrap();
    self.accounts.insert(&account, &(balance + amount));
}

}

pub fn withdraw(&mut self) { let account = env::predecessor_account_id(); let amount = self.accounts.get(&account).unwrap(); self.accounts.insert(&account, &0);

ext_ft_token::ft_transfer(compte, montant, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL);

}

2. Éviter les dépendances d'état lors des appels inter-contrats

Voici un exemple de contrat "d'enchères" :

rouille #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub registered: Vec, pub bid_price: UnorderedMap\u003caccountid,balance\u003e, pub current_leader: AccountId, pub highest_bid: u128, }

PromiseOrValue { assert!(amount > self.highest_bid);

si self.current_leader == DEFAULT_ACCOUNT {
    self.current_leader = sender_id;
    self.highest_bid = amount;
} sinon {
    ext_ft_token::account_exist(
        self.current_leader.clone)(,
        &FTTOKEN,
        0,
        env::prepaid_gas() - GAS_FOR_SINGLE_CALL * 4,
    (.then)ext_self::account_resolve)
        sender_id,
        montant,
        &env::current_account_id((,
        0,
        GAS_FOR_SINGLE_CALL * 3,
    ();
}

PromiseOrValue::Value)0)

}

#( pub fn account_resolve)&mut self, sender_id: AccountId, amount: u128[private] { match env::promise_result(0) { 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 = amount; } PromiseResult::Failed => { ext_ft_token::ft_transfer) sender_id.clone)(, montant, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL * 2, (; log!)"Return Back Now"); } PromiseResult::NotReady => unreachable!(), }; }

Le problème avec ce contrat est que si le précédent enchérisseur le plus élevé annule son compte, le nouvel enchérisseur ne pourra pas mettre à jour l'état avec succès.

La solution consiste à mettre en œuvre un traitement d'erreur raisonnable, par exemple, en plaçant les jetons non remboursables en attente, puis en permettant à l'utilisateur de les retirer lui-même par la suite:

rouille pub struct Contrat { // ... pub lost_found: UnorderedMap\u003caccountid, balance=""\u003e, }

pub fn account_resolve(&mut self, sender_id: AccountId, amount: u128) { correspondre à env::promise_result(0) { PromiseResult::Successful(_) => { // logique de remboursement normale } PromiseResult::Failed => { // Stockage des tokens non remboursables let lost_amount = self.lost_found.get(&self.current_leader).unwrap_or(0); self.lost_found.insert(&self.current_leader, &)lost_amount + self.highest_bid((;

        // Mettre à jour l'état
        self.current_leader = sender_id;
        self.highest_bid = amount;
    }
    PromiseResult::NotReady => unreachable!)),
}

}

pub fn withdraw_lost_found(&mut self) { let account = env::predecessor_account_id(); let amount = self.lost_found.get(&account).unwrap_or(0); si montant > 0 { self.lost_found.insert(&account, &0); ext_ft_token::ft_transfer(compte, montant, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL); } }

3. Éviter les points de défaillance uniques

La perte de la clé privée du propriétaire du contrat entraîne l'impossibilité d'utiliser des fonctionnalités clés. La solution consiste à adopter un mécanisme de signatures multiples:

rouille pub struct Contrat { propriétaires de pub: Vec\u003caccountid\u003e, pub required_confirmations: u64, pub transactions: Vec, }

pub fn propose_transaction(&mut self, transaction: Transaction) { assert!(self.owners.contains)&env::predecessor_account_id(((, "Not an owner"); self.transactions.push)transaction); }

pub fn confirm_transaction(&mut self, transaction_id: u64) { assert!(self.owners.contains)&env::predecessor_account_id(((, "Not an owner");

let transaction = &mut self.transactions[transaction_id as usize];
transaction.confirmations += 1;

si transaction.confirmations \u003e= self.required_confirmations {
    self.execute_transaction)transaction_id);
}

}

fn execute_transaction(&mut self, transaction_id: u64) { let transaction = self.transactions.remove(transaction_id as usize); // Exécuter la logique de transaction }

Grâce au mécanisme de multisignature, il est possible d'éviter la paralysie du contrat due à la perte de la clé privée d'un seul propriétaire, ce qui améliore le degré de décentralisation et la sécurité du contrat.

\u003c/transaction\u003e\u003c/accountid\u003e\u003c/accountid,\u003e\u003c/u128\u003e\u003c/accountid,balance\u003e\u003c/accountid\u003e\u003c/accountid,\u003e\u003c/accountid\u003e

Voir l'original
Cette page peut inclure du contenu de tiers fourni à des fins d'information uniquement. Gate ne garantit ni l'exactitude ni la validité de ces contenus, n’endosse pas les opinions exprimées, et ne fournit aucun conseil financier ou professionnel à travers ces informations. Voir la section Avertissement pour plus de détails.
  • Récompense
  • 6
  • Partager
Commentaire
0/400
TokenomicsTherapistvip
· Il y a 16h
Perdre sa clé privée, c'est tellement réel, haha
Voir l'originalRépondre0
GasFeeNightmarevip
· 08-04 04:49
Pas étonnant que ce soit un grand investisseur en gaz.
Voir l'originalRépondre0
PretendingToReadDocsvip
· 08-04 04:49
On ne peut éviter les DoS, de quoi peut-on parler de sécurité?
Voir l'originalRépondre0
HashRatePhilosophervip
· 08-04 04:32
L'armée rust arrive, tremblez adversaires.
Voir l'originalRépondre0
TestnetFreeloadervip
· 08-04 04:28
Prévenir les dos tu es dans ce piège théorie là
Voir l'originalRépondre0
MevShadowrangervip
· 08-04 04:26
Les frais de gaz explosent, je suis désespéré.
Voir l'originalRépondre0
  • Épingler
Trader les cryptos partout et à tout moment
qrCode
Scan pour télécharger Gate app
Communauté
Français (Afrique)
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)