Attaques par déni de service dans les contrats intelligents Rust
L'attaque par déni de service ( DoS ) peut rendre les smart contracts inutilisables pendant un certain temps. Les principales raisons sont les suivantes:
Il existe un défaut dans la logique du contrat qui entraîne une complexité de calcul trop élevée, ce qui provoque une consommation de Gas dépassant la limite.
Lorsqu’elle est invoquée entre contrats, l’exécution du contrat repose sur un état contractuel externe peu fiable, ce qui entraîne un blocage.
Le propriétaire du contrat perd sa clé privée, ce qui empêche l'exécution des fonctions privilégiées clés.
Nous allons analyser ces vulnérabilités DoS à travers des exemples concrets.
1. Parcourir les grandes structures de données pouvant être modifiées par des tiers
Ce qui suit est un contrat simple de « dividende » avec risque DoS :
pour cur_account dans self.registered.iter() {
let balance = self.accounts.get(&cur_account).expect("ERR_GET");
self.accounts.insert(&cur_account, &balance.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
);
}
}
Ici, self.registered peut être étendu indéfiniment, ce qui entraîne un manque de Gas lors de l'itération.
Devrait passer en mode "retrait" pour permettre aux utilisateurs de retirer volontairement des récompenses :
rouille
pub fn withdraw(&mut self) {
let account_id = env::predecessor_account_id();
let amount = self.accounts.get(&account_id).expect("Pas de récompense");
Si le compte de l’enchérisseur précédent est détruit, la nouvelle enchère sera bloquée.
Il convient de prendre en compte les cas d'échec des appels externes, et de pouvoir mettre en attente les tokens non remboursables pour que les utilisateurs puissent les extraire ultérieurement:
rouille
pub fn withdraw_lost_funds(&mut self) {
let account_id = env::predecessor_account_id();
let amount = self.lost_funds.get(&account_id).expect("No lost funds");
Certaines fonctions clés ne peuvent être appelées que par le propriétaire du contrat. Si le propriétaire perd la clé privée, ces fonctions ne seront pas exécutées.
Il convient d'adopter une solution multi-signatures pour gérer les contrats, afin d'éviter les points de défaillance uniques:
pub fn submit_transaction(&mut self, transaction: Transaction) {
assert!(self.owners.contains)&env::predecessor_account_id((();
// Ajouter la transaction à la liste d'attente de confirmation
}
pub fn confirm_transaction)&mut self, transaction_id: u64) {
assert!(self.owners.contains)&env::predecessor_account_id((();
Augmenter le nombre de confirmations
Si le nombre requis de confirmations est atteint, la transaction est exécutée
}
Grâce aux méthodes ci-dessus, le risque d’attaques DoS dans les contrats intelligents peut être efficacement évité.
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.
23 J'aime
Récompense
23
7
Partager
Commentaire
0/400
ConsensusDissenter
· 07-19 04:59
informations précieuses à collectionner et à apprendre
Guide pratique de défense contre les attaques DoS pour les smart contracts Rust
Attaques par déni de service dans les contrats intelligents Rust
L'attaque par déni de service ( DoS ) peut rendre les smart contracts inutilisables pendant un certain temps. Les principales raisons sont les suivantes:
Il existe un défaut dans la logique du contrat qui entraîne une complexité de calcul trop élevée, ce qui provoque une consommation de Gas dépassant la limite.
Lorsqu’elle est invoquée entre contrats, l’exécution du contrat repose sur un état contractuel externe peu fiable, ce qui entraîne un blocage.
Le propriétaire du contrat perd sa clé privée, ce qui empêche l'exécution des fonctions privilégiées clés.
Nous allons analyser ces vulnérabilités DoS à travers des exemples concrets.
1. Parcourir les grandes structures de données pouvant être modifiées par des tiers
Ce qui suit est un contrat simple de « dividende » avec risque DoS :
rouille #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub enregistré : Vec, pub accounts : UnorderedMap<accountid, balance="">, }
pub fn register_account(&mut self) { if self.accounts.insert(&env::predecessor_account_id(), &0).is_some() { env ::p anic("Le compte est déjà enregistré ».to_string().as_ bytes()) ; } else { self.registered.push(env ::p compte_redecessor_id()) ; } log!("Compte enregistré {}", env::predecessor_account_id()); }
pub fn distribute_token(&mut self, montant : u128) { assert_eq!(env::predecessor_account_id(), DISTRIBUTEUR, "ERR_NOT_ALLOWED");
}
Ici, self.registered peut être étendu indéfiniment, ce qui entraîne un manque de Gas lors de l'itération.
Devrait passer en mode "retrait" pour permettre aux utilisateurs de retirer volontairement des récompenses :
rouille pub fn withdraw(&mut self) { let account_id = env::predecessor_account_id(); let amount = self.accounts.get(&account_id).expect("Pas de récompense");
}
2. La dépendance d'état entre contrats croisés entraîne un blocage
Voici un contrat de "enchère" :
rouille #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub enregistré : Vec, pub bid_price : UnorderedMap<accountid, balance="">, pub current_leader: AccountId, highest_bid pub : U128, pub remboursement: bool }
PromiseOrValue { affirmer !(amount > self.highest_bid) ;
}
#( pub fn account_resolve)&mut self, sender_id : AccountId, amount : u128[private] { match env::promise_result(0) { PromiseResult ::NotReady => inaccessible !(), 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 !)"Reviens maintenant") ; } }; }
Si le compte de l’enchérisseur précédent est détruit, la nouvelle enchère sera bloquée.
Il convient de prendre en compte les cas d'échec des appels externes, et de pouvoir mettre en attente les tokens non remboursables pour que les utilisateurs puissent les extraire ultérieurement:
rouille pub fn withdraw_lost_funds(&mut self) { let account_id = env::predecessor_account_id(); let amount = self.lost_funds.get(&account_id).expect("No lost funds");
}
!
3. Clé privée du propriétaire perdue
Certaines fonctions clés ne peuvent être appelées que par le propriétaire du contrat. Si le propriétaire perd la clé privée, ces fonctions ne seront pas exécutées.
Il convient d'adopter une solution multi-signatures pour gérer les contrats, afin d'éviter les points de défaillance uniques:
rouille pub struct MultiSigContract { propriétaires : Vec\u003caccountid\u003e, required_confirmations: u32, }
pub fn submit_transaction(&mut self, transaction: Transaction) { assert!(self.owners.contains)&env::predecessor_account_id(((); // Ajouter la transaction à la liste d'attente de confirmation }
pub fn confirm_transaction)&mut self, transaction_id: u64) { assert!(self.owners.contains)&env::predecessor_account_id(((); Augmenter le nombre de confirmations Si le nombre requis de confirmations est atteint, la transaction est exécutée }
Grâce aux méthodes ci-dessus, le risque d’attaques DoS dans les contrats intelligents peut être efficacement évité.
! [])https ://img-cdn.gateio.im/social/moments-7076cf1226a2276d1e4cd994d259841f019283746574839201</accountid,></accountid,>