Rust hợp đồng thông minh an toàn: phòng ngừa tấn công từ chối dịch vụ
tấn công từ chối dịch vụ(DoS) sẽ dẫn đến hợp đồng thông minh không thể được sử dụng bình thường trong một khoảng thời gian, thậm chí có thể bị tê liệt vĩnh viễn. Nguyên nhân chính bao gồm:
Hợp đồng thông minh có khuyết điểm về độ phức tạp tính toán, dẫn đến việc tiêu tốn Gas vượt quá giới hạn.
Sự phụ thuộc vào trạng thái thực thi của hợp đồng bên ngoài khi gọi hợp đồng chéo có thể bị hợp đồng bên ngoài chặn.
Chủ hợp đồng mất khóa riêng, không thể thực hiện các chức năng đặc quyền quan trọng.
Dưới đây sẽ phân tích kết hợp với các ví dụ cụ thể.
1. Tránh duyệt qua các cấu trúc dữ liệu lớn có thể bị thao túng từ bên ngoài
Dưới đây là một hợp đồng "chia thưởng" đơn giản, có nguy cơ tấn công từ chối dịch vụ:
gỉ
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct Hợp đồng {
pub registered: Vec\u003caccountid\u003e,
pub accounts: UnorderedMap\u003caccountid, balance=""\u003e,
}
pub fn register_account(&mut self) {
nếu self.accounts.insert(&env::predecessor_account_id(), &0).is_some() {
env::panic("Tài khoản đã được đăng ký".to_string().as_bytes());
} else {
self.registered.push(env::predecessor_account_id());
}
log!("Tài khoản đã đăng ký {}", env::predecessor_account_id());
}
cho cur_account trong 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!("Cố gắng phân phối cho tài khoản {}", &cur_account);
ext_ft_token::ft_transfer(
cur_account.clone(),
số lượng,
&FTTOKEN,
0,
GAS_FOR_SINGLE_CALL
);
}
}
Vấn đề của hợp đồng này là kích thước của mảng registered không có giới hạn, có thể bị người dùng ác ý thao tác khiến nó quá lớn, dẫn đến việc hàm distribute_token tiêu tốn Gas vượt quá giới hạn.
Giải pháp được đề xuất là áp dụng chế độ "rút tiền":
cho tài khoản trong self.registered.iter() {
let balance = self.accounts.get(&account).unwrap();
self.accounts.insert(\u0026account, \u0026(balance + amount));
}
}
pub fn withdraw(&mut self) {
let account = env::predecessor_account_id();
let amount = self.accounts.get(&account).unwrap();
self.accounts.insert(\u0026account, \u00260);
ext_ft_token::ft_transfer(tài khoản, số tiền, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL);
}
2. Tránh phụ thuộc trạng thái trong gọi hợp đồng chéo
pub fn withdraw_lost_found(&mut self) {
let account = env::predecessor_account_id();
let amount = self.lost_found.get(&account).unwrap_or(0);
nếu số lượng > 0 {
self.lost_found.insert(&account, &0);
ext_ft_token::ft_transfer(account, amount, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL);
}
}
3. Tránh điểm lỗi đơn
Mất khóa riêng của chủ hợp đồng sẽ dẫn đến việc các chức năng đặc quyền quan trọng không thể sử dụng. Giải pháp là áp dụng cơ chế ký đa.
gỉ
pub struct Hợp đồng {
chủ sở hữu pub: Vec\u003caccountid\u003e,
pub required_confirmations: u64,
pub transactions: Vec,
}
pub fn propose_transaction(&mut self, transaction: Transaction) {
assert!(self.owners.contains)&env::predecessor_account_id(((, "Không phải là chủ sở hữu");
self.transactions.push)transaction);
}
pub fn confirm_transaction(&mut self, transaction_id: u64) {
assert!(self.owners.contains)&env::predecessor_account_id(((, "Không phải là chủ sở hữu");
let transaction = &mut self.transactions[transaction_id as usize];
transaction.confirmations += 1;
nếu transaction.confirmations >= self.required_confirmations {
self.execute_transaction)transaction_id);
}
}
fn execute_transaction(&mut self, transaction_id: u64) {
let transaction = self.transactions.remove(transaction_id as usize);
// Thực hiện logic giao dịch
}
Thông qua cơ chế ký đa chữ ký, có thể tránh được việc hợp đồng bị tê liệt do mất khóa riêng của một chủ sở hữu duy nhất, từ đó nâng cao mức độ phi tập trung và an toàn của hợp đồng.
Trang này có thể chứa nội dung của bên thứ ba, được cung cấp chỉ nhằm mục đích thông tin (không phải là tuyên bố/bảo đảm) và không được coi là sự chứng thực cho quan điểm của Gate hoặc là lời khuyên về tài chính hoặc chuyên môn. Xem Tuyên bố từ chối trách nhiệm để biết chi tiết.
7 thích
Phần thưởng
7
6
Chia sẻ
Bình luận
0/400
TokenomicsTherapist
· 1giờ trước
Đánh mất khóa riêng thật sự quá hài hước hahaha
Xem bản gốcTrả lời0
GasFeeNightmare
· 08-04 04:49
Không hổ danh là Nhà đầu tư lớn Gas
Xem bản gốcTrả lời0
PretendingToReadDocs
· 08-04 04:49
DoS vẫn không thể tránh khỏi, còn an toàn gì để nói nữa?
Rust hợp đồng thông minh an toàn: 3 chiến lược then chốt để phòng ngừa tấn công DoS
Rust hợp đồng thông minh an toàn: phòng ngừa tấn công từ chối dịch vụ
tấn công từ chối dịch vụ(DoS) sẽ dẫn đến hợp đồng thông minh không thể được sử dụng bình thường trong một khoảng thời gian, thậm chí có thể bị tê liệt vĩnh viễn. Nguyên nhân chính bao gồm:
Hợp đồng thông minh có khuyết điểm về độ phức tạp tính toán, dẫn đến việc tiêu tốn Gas vượt quá giới hạn.
Sự phụ thuộc vào trạng thái thực thi của hợp đồng bên ngoài khi gọi hợp đồng chéo có thể bị hợp đồng bên ngoài chặn.
Chủ hợp đồng mất khóa riêng, không thể thực hiện các chức năng đặc quyền quan trọng.
Dưới đây sẽ phân tích kết hợp với các ví dụ cụ thể.
1. Tránh duyệt qua các cấu trúc dữ liệu lớn có thể bị thao túng từ bên ngoài
Dưới đây là một hợp đồng "chia thưởng" đơn giản, có nguy cơ tấn công từ chối dịch vụ:
gỉ #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Hợp đồng { pub registered: Vec\u003caccountid\u003e, pub accounts: UnorderedMap\u003caccountid, balance=""\u003e, }
pub fn register_account(&mut self) { nếu self.accounts.insert(&env::predecessor_account_id(), &0).is_some() { env::panic("Tài khoản đã được đăng ký".to_string().as_bytes()); } else { self.registered.push(env::predecessor_account_id()); } log!("Tài khoản đã đăng ký {}", env::predecessor_account_id()); }
pub fn distribute_token(&mut self, amount: u128) { assert_eq!(env::predecessor_account_id(), DISTRIBUTOR, "ERR_NOT_ALLOWED");
}
Vấn đề của hợp đồng này là kích thước của mảng registered không có giới hạn, có thể bị người dùng ác ý thao tác khiến nó quá lớn, dẫn đến việc hàm distribute_token tiêu tốn Gas vượt quá giới hạn.
Giải pháp được đề xuất là áp dụng chế độ "rút tiền":
gỉ pub fn distribute_token(&mut self, amount: u128) { assert_eq!(env::predecessor_account_id(), DISTRIBUTOR, "ERR_NOT_ALLOWED");
}
pub fn withdraw(&mut self) { let account = env::predecessor_account_id(); let amount = self.accounts.get(&account).unwrap(); self.accounts.insert(\u0026account, \u00260);
}
2. Tránh phụ thuộc trạng thái trong gọi hợp đồng chéo
Dưới đây là một ví dụ về hợp đồng "đấu giá":
gỉ #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Hợp đồng { pub registered: Vec\u003caccountid\u003e, pub bid_price: UnorderedMap\u003caccountid,balance\u003e, pub current_leader: AccountId, pub highest_bid: u128, }
PromiseOrValue { assert!(amount > self.highest_bid);
}
#( pub fn account_resolve)&mut self, sender_id: AccountId, amount: u128[private] { match env::promise_result(0) { 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)(, số lượng, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL * 2, (; log!)"Trở về ngay bây giờ"); } PromiseResult::NotReady => unreachable!(), }; }
Vấn đề của hợp đồng này là nếu người đấu giá cao nhất trước đó hủy bỏ tài khoản, người đấu giá mới sẽ không thể cập nhật trạng thái thành công.
Giải pháp là thực hiện xử lý lỗi hợp lý, chẳng hạn như tạm giữ các token không thể hoàn lại, sau đó để người dùng tự rút lại.
gỉ pub struct Hợp đồng { // ... pub lost_found: UnorderedMap<accountid, balance="">, }
pub fn account_resolve(&mut self, sender_id: AccountId, amount: u128) { match env::promise_result(0) { PromiseResult::Successful(_) => { // Logic hoàn tiền bình thường } PromiseResult::Failed => {
// Tạm giữ token không thể hoàn trả let lost_amount = self.lost_found.get(&self.current_leader).unwrap_or(0); self.lost_found.insert(&self.current_leader, &)lost_amount + self.highest_bid((;
}
pub fn withdraw_lost_found(&mut self) { let account = env::predecessor_account_id(); let amount = self.lost_found.get(&account).unwrap_or(0); nếu số lượng > 0 { self.lost_found.insert(&account, &0); ext_ft_token::ft_transfer(account, amount, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL); } }
3. Tránh điểm lỗi đơn
Mất khóa riêng của chủ hợp đồng sẽ dẫn đến việc các chức năng đặc quyền quan trọng không thể sử dụng. Giải pháp là áp dụng cơ chế ký đa.
gỉ pub struct Hợp đồng { chủ sở hữu pub: Vec\u003caccountid\u003e, pub required_confirmations: u64, pub transactions: Vec, }
pub fn propose_transaction(&mut self, transaction: Transaction) { assert!(self.owners.contains)&env::predecessor_account_id(((, "Không phải là chủ sở hữu"); self.transactions.push)transaction); }
pub fn confirm_transaction(&mut self, transaction_id: u64) { assert!(self.owners.contains)&env::predecessor_account_id(((, "Không phải là chủ sở hữu");
}
fn execute_transaction(&mut self, transaction_id: u64) { let transaction = self.transactions.remove(transaction_id as usize); // Thực hiện logic giao dịch }
Thông qua cơ chế ký đa chữ ký, có thể tránh được việc hợp đồng bị tê liệt do mất khóa riêng của một chủ sở hữu duy nhất, từ đó nâng cao mức độ phi tập trung và an toàn của hợp đồng.