Guide pratique de prévention des attaques DoS sur les smart contracts Rust

Journal de développement des smart contracts en Rust : prévention des attaques par déni de service

L'attaque par déni de service ( DoS ) peut entraîner l'incapacité des smart contracts à fonctionner normalement pendant une période de temps, voire de manière permanente. Les causes courantes incluent :

  1. Le problème de la complexité des calculs dans la logique des contrats entraîne une consommation de Gas dépassant la limite.

  2. Lors des appels inter-contrats, une dépendance inappropriée à l'état d'exécution des contrats externes entraîne le blocage de ce contrat.

  3. La clé privée du propriétaire du contrat est perdue, ce qui empêche l'appel des fonctions privilégiées et la mise à jour de l'état système important.

Voici quelques exemples concrets pour analyser les vulnérabilités des attaques par déni de service (DoS) et leurs solutions.

1. Parcourir en boucle des structures de données volumineuses pouvant être modifiées de l'extérieur

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 Contract { pub registered: Vec\u003caccountid\u003e, pub accounts: UnorderedMap\u003caccountid, balance=""\u003e, }

impl Contrat { pub fn register_account(&mut self) { if self.accounts.insert(&env::predecessor_account_id(), &0).is_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!("Essayer de distribuer au compte {}", &cur_account);
        
        ext_ft_token::ft_transfer(
            cur_account.clone(),
            montant,
            &FTTOKEN,
            0,
            GAS_FOR_SINGLE_CALL
        );
    }
}

}

Le problème est que la taille du tableau registered n'est pas limitée, ce qui permet à des utilisateurs malveillants de le manipuler pour le rendre trop grand, entraînant une consommation de Gas dépassant la limite lors de l'exécution de la fonction distribute_token.

Suggestions de solution :

  1. Limiter la taille du tableau registered.

  2. Adopter le mode "retrait" permettant aux utilisateurs de retirer eux-mêmes les récompenses, au lieu que le contrat les distribue activement.

2. La dépendance d'état entre contrats entraîne le blocage des contrats

Voici un exemple de contrat "enchère" :

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, pub refund: bool }

impl Contrat { PromiseOrValue { assert!(montant > self.highest_bid);

    si self.current_leader == DEFAULT_ACCOUNT {
        self.current_leader = sender_id;
        self.highest_bid = amount;
    } 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
    );
    PromiseOrValue::Value(0)
}

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

}

Le problème est que la mise à jour de l'état du contrat dépend des appels de contrats externes. Si le compte du précédent enchérisseur le plus élevé a été annulé, les enchérisseurs suivants ne pourront pas mettre à jour l'état.

Suggestions de solution :

Considérer les cas où les appels externes peuvent échouer et mettre en œuvre un mécanisme de gestion des erreurs raisonnable. Par exemple, stocker temporairement les tokens non remboursables dans le contrat, permettant par la suite à l'utilisateur de les retirer de manière proactive.

3. Clé privée du propriétaire perdue

De nombreux contrats contiennent des fonctions privilégiées qui ne peuvent être exécutées que par le propriétaire. Si la clé privée du propriétaire est perdue, ces fonctions ne pourront pas être appelées, ce qui peut entraîner un dysfonctionnement du contrat.

Suggestions de solution :

  1. Configurer plusieurs propriétaires de contrats pour une gestion conjointe.

  2. Adopter un mécanisme de multi-signature pour remplacer le contrôle d'un seul propriétaire.

  3. Réaliser un mécanisme de gouvernance de contrat décentralisé.

Grâce aux mesures ci-dessus, il est possible de réduire efficacement le risque d'attaque par déni de service dans les smart contracts, tout en améliorant la sécurité et la fiabilité des contrats.

<accountid,balance><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
  • 8
  • Partager
Commentaire
0/400
MEVHunterWangvip
· Il y a 8h
Ce n'est pas difficile de jouer avec un contrat.
Voir l'originalRépondre0
ProofOfNothingvip
· Il y a 12h
Encore du formalisme et des discours théoriques.
Voir l'originalRépondre0
LuckyHashValuevip
· Il y a 15h
L'attaque n'a pas été arrêtée, on va encore tomber à zéro.
Voir l'originalRépondre0
ColdWalletGuardianvip
· Il y a 15h
Blockchain entrée équipement standard de connaissances
Voir l'originalRépondre0
SelfSovereignStevevip
· Il y a 16h
La perte de la clé privée serait terrible.
Voir l'originalRépondre0
StableBoivip
· Il y a 16h
Ce contrat présente en effet pas mal de risques, sa stabilité n'est pas vraiment au rendez-vous.
Voir l'originalRépondre0
Ser_This_Is_A_Casinovip
· Il y a 16h
Ah~ Rust est vraiment difficile, pourquoi ne pas envisager Solidity
Voir l'originalRépondre0
GasFeeThundervip
· Il y a 16h
gas mange trop et ça fait quoi ? Le contrat sera tôt ou tard vidé.
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)