Análise de ataque de negação de serviço em contratos inteligentes
ataque de negação de serviço(DoS)pode levar a que os contratos inteligentes não possam ser utilizados normalmente durante um período de tempo ou até mesmo permanentemente. As principais razões incluem:
Defeitos na lógica do contrato, como a complexidade de cálculo excessiva de certas funções públicas, levando ao consumo de Gas a ultrapassar o limite.
A dependência do estado de execução de contratos externos durante chamadas de contratos cruzados, a execução de contratos externos pode ser pouco confiável e pode bloquear o funcionamento normal deste contrato.
Fatores humanos, como a perda da chave privada pelo proprietário do contrato, que impede a chamada de certas funções privilegiadas.
Abaixo, analisamos a vulnerabilidade de ataque de negação de serviço (DoS) em contratos inteligentes através de exemplos concretos.
1. Percorrendo estruturas de dados grandes que podem ser modificadas externamente
Segue um contrato simples para "distribuição de dividendos" aos usuários registrados:
pub fn register_account(&mut self) {
if self.accounts.insert(&env::predecessor_account_id(), &0).is_some() {
env::panic('A conta já está registrada'.to_string().as_bytes());
}else{
self.registered.push(env::predecessor_account_id());
}
log!('Conta registada{}',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(&cur_account).expect('ERR_GET');
self.accounts.insert(&cur_account,&balance.checked_add(amount).expect('ERR_ADD'));
log!('Tentar distribuir para a conta{}',&cur_account);
ext_ft_token::ft_transfer(
cur_account.clone(),
montante,
&FTTOKEN,
0,
GAS_FOR_SINGLE_CALL
);
}
}
O problema do contrato é que o tamanho do array self.registered não tem limite, podendo ser manipulado por usuários mal-intencionados para se tornar excessivamente grande, levando a um consumo de Gas que ultrapassa o limite ao executar a função distribute_token.
Soluções recomendadas:
Limitar o comprimento máximo do array self.registered
Adotar o modo de retirada, não percorrer proativamente a distribuição de recompensas, mas permitir que os usuários chamem a função de retirada por conta própria.
2. A interdependência de estado entre contratos leva ao bloqueio de contratos
O problema do contrato é que, se a conta do utilizador com a maior oferta atual for cancelada no contrato de token externo, a nova oferta mais alta não poderá devolver os tokens do anterior, levando ao bloqueio do processo de licitação.
Solução:
Considerar a possibilidade de que chamadas de contratos externos possam falhar e implementar um tratamento de erros razoável. Por exemplo, armazenar temporariamente tokens não recuperáveis no contrato, permitindo posteriormente que os usuários os retirem por conta própria.
3. Perda da chave privada do proprietário do contrato
Nos contratos inteligentes, muitas vezes existem funções privilegiadas que só podem ser executadas pelo proprietário. Se a chave privada do proprietário for perdida, essas funções não poderão ser chamadas, o que pode levar o contrato a não funcionar corretamente.
Solução:
Definir vários proprietários de contratos para governança conjunta
Adotar um mecanismo de múltiplas assinaturas em vez do controle de permissões de um único proprietário
Implementar uma solução de governança de contratos descentralizados
</accountid,balance></accountid,>
Ver original
Esta página pode conter conteúdos de terceiros, que são fornecidos apenas para fins informativos (sem representações/garantias) e não devem ser considerados como uma aprovação dos seus pontos de vista pela Gate, nem como aconselhamento financeiro ou profissional. Consulte a Declaração de exoneração de responsabilidade para obter mais informações.
15 gostos
Recompensa
15
7
Partilhar
Comentar
0/400
consensus_whisperer
· 07-31 14:18
Quem você está dizendo que é inexperiente e adora brincar com contratos?
Ver originalResponder0
RumbleValidator
· 07-30 19:13
Mais uma vez, um simples bug de loop infinito. Antes de fazer o dump do contrato, a validação da pressão no nó deve ser levada ao limite.
Ver originalResponder0
GasGuzzler
· 07-30 19:12
Especialista em desincentivar taxas de GAS! Explosão direta.
Ver originalResponder0
BtcDailyResearcher
· 07-30 19:10
Mais alguém foi enganado pelo DoS. Estou a rir até morrer.
Ver originalResponder0
SignatureDenied
· 07-30 19:05
Outra vez atacado? Quem ainda se atreve a guardar a chave privada de forma descuidada?
Ver originalResponder0
DefiOldTrickster
· 07-30 19:02
O velho Bai brincou tanto no Bear Market que teve um contrato bloqueado por uma chave privada perdida. Que triste!
Ver originalResponder0
RuntimeError
· 07-30 18:53
Hum? O contrato pode ser encerrado por causa de perda da chave privada? Isso é realmente urgente.
Profundidade da análise das vulnerabilidades de ataque DoS em contratos inteligentes e estratégias de prevenção
Análise de ataque de negação de serviço em contratos inteligentes
ataque de negação de serviço(DoS)pode levar a que os contratos inteligentes não possam ser utilizados normalmente durante um período de tempo ou até mesmo permanentemente. As principais razões incluem:
Defeitos na lógica do contrato, como a complexidade de cálculo excessiva de certas funções públicas, levando ao consumo de Gas a ultrapassar o limite.
A dependência do estado de execução de contratos externos durante chamadas de contratos cruzados, a execução de contratos externos pode ser pouco confiável e pode bloquear o funcionamento normal deste contrato.
Fatores humanos, como a perda da chave privada pelo proprietário do contrato, que impede a chamada de certas funções privilegiadas.
Abaixo, analisamos a vulnerabilidade de ataque de negação de serviço (DoS) em contratos inteligentes através de exemplos concretos.
1. Percorrendo estruturas de dados grandes que podem ser modificadas externamente
Segue um contrato simples para "distribuição de dividendos" aos usuários registrados:
ferrugem #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub registrado: Vec\u003caccountid\u003e, pub accounts: UnorderedMap\u003caccountid, balance=""\u003e, }
pub fn register_account(&mut self) { if self.accounts.insert(&env::predecessor_account_id(), &0).is_some() { env::panic('A conta já está registrada'.to_string().as_bytes()); }else{ self.registered.push(env::predecessor_account_id()); } log!('Conta registada{}',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(&cur_account).expect('ERR_GET'); self.accounts.insert(&cur_account,&balance.checked_add(amount).expect('ERR_ADD')); log!('Tentar distribuir para a conta{}',&cur_account); ext_ft_token::ft_transfer( cur_account.clone(), montante, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL ); } }
O problema do contrato é que o tamanho do array self.registered não tem limite, podendo ser manipulado por usuários mal-intencionados para se tornar excessivamente grande, levando a um consumo de Gas que ultrapassa o limite ao executar a função distribute_token.
Soluções recomendadas:
2. A interdependência de estado entre contratos leva ao bloqueio de contratos
Considere um contrato de "licitação":
ferrugem #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub registered: Vec\u003caccountid\u003e, pub bid_price: UnorderedMap\u003caccountid,balance\u003e, pub current_leader: AccountId, pub highest_bid: u128, pub refund: bool }
PromiseOrValue { assert!(amount > self.highest_bid); se 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, montante, &env::current_account_id((, 0, GAS_FOR_SINGLE_CALL * 3, (); } log!) 'líder_atual: {} maior_lance: {}', 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 = amount; } PromiseResult::Failed => { ext_ft_token::ft_transfer) sender_id.clone)(, montante, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL * 2, (; log!)'Recuar Agora'); } }; }
O problema do contrato é que, se a conta do utilizador com a maior oferta atual for cancelada no contrato de token externo, a nova oferta mais alta não poderá devolver os tokens do anterior, levando ao bloqueio do processo de licitação.
Solução:
Considerar a possibilidade de que chamadas de contratos externos possam falhar e implementar um tratamento de erros razoável. Por exemplo, armazenar temporariamente tokens não recuperáveis no contrato, permitindo posteriormente que os usuários os retirem por conta própria.
3. Perda da chave privada do proprietário do contrato
Nos contratos inteligentes, muitas vezes existem funções privilegiadas que só podem ser executadas pelo proprietário. Se a chave privada do proprietário for perdida, essas funções não poderão ser chamadas, o que pode levar o contrato a não funcionar corretamente.
Solução: