Guía práctica para la prevención de ataques DoS en contratos inteligentes Rust

Diario de desarrollo de contratos inteligentes en Rust: prevención de ataque de denegación de servicio

El ataque de denegación de servicio ( DoS ) puede hacer que los contratos inteligentes no funcionen correctamente durante un tiempo o incluso de forma permanente. Las causas comunes incluyen:

  1. El problema de la complejidad de cálculo en la lógica del contrato, que provoca que el consumo de Gas supere el límite.

  2. Al realizar llamadas a contratos cruzados, la dependencia inapropiada del estado de ejecución de contratos externos puede provocar que este contrato quede bloqueado.

  3. La pérdida de la clave privada del propietario del contrato provoca que las funciones privilegiadas no se puedan llamar y que el estado importante del sistema no se pueda actualizar.

A continuación, analizaremos las vulnerabilidades de ataque de denegación de servicio (DoS) y sus soluciones a través de algunos ejemplos específicos.

1. Recorrer estructuras de datos grandes que pueden ser modificadas externamente

A continuación se presenta un simple contrato de "dividendo", que presenta un riesgo de ataque de denegación de servicio:

óxido #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub registered: Vec\u003caccountid\u003e, pub accounts: UnorderedMap\u003caccountid, balance=""\u003e, }

impl Contract { pub fn register_account(&mut self) { if self.accounts.insert(&env::predecessor_account_id(), &0).is_some() { env::panic("La cuenta ya está registrada".to_string().as_bytes()); } else { self.registered.push(env::predecessor_account_id()); } log!("Cuenta registrada {}", env::predecessor_account_id()); }

pub fn distribute_token(&mut self, amount: u128) {
    assert_eq!(env::predecessor_account_id(), DISTRIBUTOR, "ERR_NOT_ALLOWED");
    
    for cur_account in self.registered.iter() {
        let balance = self.accounts.get(\u0026cur_account).expect("ERR_GET");
        self.accounts.insert(\u0026cur_account, \u0026balance.checked_add(amount).expect("ERR_ADD"));
        log!("Intente distribuir a la cuenta {}", &cur_account);
        
        ext_ft_token::ft_transfer(
            cur_account.clone(),
            cantidad,
            &FTTOKEN,
            0,
            GAS_FOR_SINGLE_CALL
        );
    }
}

}

El problema es que el tamaño del array registered no tiene límite, lo que puede ser manipulado por usuarios maliciosos para volverse demasiado grande, lo que lleva a que el consumo de Gas al ejecutar la función distribute_token supere el límite.

Sugerencia de solución:

  1. Restringir el tamaño del arreglo registered.

  2. Adoptar el modo de "retiro", permitiendo a los usuarios extraer sus recompensas por sí mismos, en lugar de que el contrato las distribuya activamente.

2. La dependencia de estado entre contratos cruzados provoca el bloqueo del contrato

A continuación se muestra un ejemplo de contrato de "subasta":

óxido #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub registered: Vec, pub bid_price: UnorderedMap<accountid,balance>, pub current_leader: AccountId, pub highest_bid: u128, pub reembolso: bool }

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

    if 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,
            cantidad,
            &env::current_account_id((,
            0,
            GAS_FOR_SINGLE_CALL * 3,
        ();
    }

    log!)
        "líder_actual: {} oferta_más_alta: {}", 
        self.current_leader,
        self.highest_bid
    );
    PromiseOrValue::Value(0)
}

#(
pub fn account_resolve)&mut self, sender_id: AccountId, amount: u128[private] {
    coincidir env::resultado_promesa(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 = amount;
        }
        PromiseResult::Failed => {
            ext_ft_token::ft_transfer)
                sender_id.clone)(,
                cantidad,
                &FTTOKEN,
                0,
                GAS_FOR_SINGLE_CALL * 2,
            (;
            log!)"Regresar Ahora");
        }
    };
}

}

El problema es que la actualización del estado del contrato depende de las llamadas a contratos externos. Si la cuenta del anterior postor más alto ha sido cancelada, los postores posteriores no podrán actualizar el estado.

Sugerencia de solución:

Considerar la posibilidad de que las llamadas externas puedan fallar y implementar un mecanismo de manejo de errores razonable. Por ejemplo, almacenar temporalmente los tokens no reembolsables en el contrato y permitir que los usuarios los retiren proactivamente más adelante.

3. Pérdida de la clave privada del propietario

Muchos contratos tienen funciones privilegiadas que solo el propietario puede ejecutar. Si se pierde la clave privada del propietario, estas funciones no podrán ser llamadas, lo que puede llevar a que el contrato no funcione correctamente.

Sugerencia de solución:

  1. Configurar múltiples propietarios de contratos para gestionar conjuntamente.

  2. Utilizar un mecanismo de múltiples firmas para reemplazar el control de un único propietario.

  3. Implementar un mecanismo de gobernanza de contratos descentralizados.

A través de las medidas anteriores, se puede reducir eficazmente el riesgo de ataque de denegación de servicio en los contratos inteligentes, mejorando la seguridad y confiabilidad del contrato.

<accountid,balance><accountid,>

Ver originales
Esta página puede contener contenido de terceros, que se proporciona únicamente con fines informativos (sin garantías ni declaraciones) y no debe considerarse como un respaldo por parte de Gate a las opiniones expresadas ni como asesoramiento financiero o profesional. Consulte el Descargo de responsabilidad para obtener más detalles.
  • Recompensa
  • 8
  • Compartir
Comentar
0/400
MEVHunterWangvip
· hace7h
¿No es fácil jugar con un contrato si tienes el control?
Ver originalesResponder0
ProofOfNothingvip
· hace11h
Es otra vez un discurso vacío y formalista.
Ver originalesResponder0
LuckyHashValuevip
· hace14h
El ataque no se detuvo, ahora va a caer a cero.
Ver originalesResponder0
ColdWalletGuardianvip
· hace14h
Conocimientos básicos estándar de introducción a la Cadena de bloques
Ver originalesResponder0
SelfSovereignStevevip
· hace14h
Llave privada perdida sería un desastre
Ver originalesResponder0
StableBoivip
· hace14h
Este contrato realmente tiene un poco de riesgo, su estabilidad no es muy buena.
Ver originalesResponder0
Ser_This_Is_A_Casinovip
· hace15h
Ah, Rust es realmente difícil, mejor considerar Solidity.
Ver originalesResponder0
GasFeeThundervip
· hace15h
¿Gas comiendo demasiado y causando problemas? Tarde o temprano el contrato será limpiado.
Ver originalesResponder0
Opere con criptomonedas en cualquier momento y lugar
qrCode
Escanee para descargar la aplicación Gate
Comunidad
Español
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)