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:

  1. 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.

  2. 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.

  3. 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");

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");

self.accounts.insert(&account_id, &0) ;

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

}

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) ;

if self.current_leader == DEFAULT_ACCOUNT {
    self.current_leader = sender_id ;
    self.highest_bid = montant ;
} else {
    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,
    ();
}

log!)
    « current_leader : {} highest_bid : {} »,
    self.current_leader,
    self.highest_bid
);

PromettreOuValeur ::Value(0)

}

#( 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");

self.lost_funds.remove(&account_id);

ext_ft_token ::ft_transfer(
    account_id,
    quantité
    &FTTOKEN,
    0,
    GAS_FOR_SINGLE_CALL
);

}

!

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,>

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
  • 7
  • Partager
Commentaire
0/400
ConsensusDissentervip
· 07-19 04:59
informations précieuses à collectionner et à apprendre
Voir l'originalRépondre0
MEVHunterZhangvip
· 07-18 23:52
C'est vraiment un conseil d'expert.
Voir l'originalRépondre0
PumpBeforeRugvip
· 07-18 15:28
Qui paie les frais de gaz ?
Voir l'originalRépondre0
GmGnSleepervip
· 07-17 00:43
La sécurité avant tout, c'est sans faute.
Voir l'originalRépondre0
ImpermanentPhilosophervip
· 07-17 00:41
Il suffit de redémarrer de force.
Voir l'originalRépondre0
GasFeePhobiavip
· 07-17 00:23
Les frais de gaz sont un gros problème.
Voir l'originalRépondre0
AllInAlicevip
· 07-17 00:21
L’optimisation des gaz est importante
Voir l'originalRépondre0
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)