安全问题
1.可能的错误
智能合约终止
限制转账限额 限制速率
有效途径来进行bug修复和提升
2.谨慎发布智能合约
对智能合约进行彻底的测试 并在任何新的攻击手法被发现后及时制止
赏金计划和审计合约
3.合约的简介
确保智能合约逻辑简单
确保合约和函数模块化
4.保持更新
在任何新发现的漏洞之前进行修复
利用最新技术
5.潜在特性
可能会调用同名函数
漏洞
溢出漏洞
typedef struct acnts {
account_name name0;
account_name name1;
account_name name2;
account_name name3;
} account_names;
void transfer(symbol_name symbol, account_name from, account_names to, uint64_t balance)
{
require_auth(from);
account fromaccount;
require_recipient(from);
require_recipient(to.name0);
require_recipient(to.name1);
require_recipient(to.name2);
require_recipient(to.name3);
eosio_assert(is_balance_within_range(balance), "invalid balance");
eosio_assert(balance > 0, "must transfer positive balance");
uint64_t amount = balance * 4; //乘法溢出
int itr = db_find_i64(_self, symbol, N(table), from);
eosio_assert(itr >= 0, "Sub-- wrong name");
db_get_i64(itr, &fromaccount, (account));
eosio_assert(fromaccount.balance >= amount, "overdrawn balance");
sub_balance(symbol, from, amount);
add_balance(symbol, to.name0, balance);
add_balance(symbol, to.name1, balance);
add_balance(symbol, to.name2, balance);
add_balance(symbol, to.name3, balance);
}
提示 使用assert进行检查 而不是把balance提出来进行运算
权限校验
严格判断入参函数和实际调用使得否一致
void token::transfer( account_name from,
account_name to,
asset quantity,
string memo )
{
eosio_assert( from != to, "cannot transfer to self" );
eosio_assert( is_account( to ), "to account does not exist");
auto sym = quantity.symbol.name();
stats statstable( _self, sym );
const auto& st = statstable.get( sym );
require_recipient( from );
require_recipient( to );
eosio_assert( quantity.is_valid(), "invalid quantity" );
eosio_assert( quantity.amount > 0, "must transfer positive quantity" );
eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" );
auto payer = has_auth( to ) ? to : from;
sub_balance( from, quantity );
add_balance( to, quantity, payer );
}
提示:检验资产转出账户和调用账户是否一致
确保每一个action和code满足关联要求
// extend from EOSIO_ABI
define EOSIO_ABI_EX( TYPE, MEMBERS ) \
extern "C" {
void apply( uint64_t receiver, uint64_t code, uint64_t action ) {
auto self = receiver;
if( action == N(onerror)) {
/* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission /
eosio_assert(code == N(eosio), "onerror action's are only valid from the "eosio" system account");
}
if( code == self || code == N(eosio.token) || action == N(onerror) ) {
TYPE thiscontract( self );
switch( action ) {
EOSIO_API( TYPE, MEMBERS )
}
/ does not allow destructor of thiscontract to run: eosio_exit(0); */
}
}
}
EOSIO_ABI_EX(eosio::charity, (hi)(transfer))
提示:关键检查
相关文章:
eosbet被盗事件合约分析
被盗合约 受攻击代码
有问题的合约代码
// extend from EOSIO_ABI, because we need to listen to incoming eosio.token transfers
define EOSIO_ABI_EX( TYPE, MEMBERS ) \
extern "C" {
void apply( uint64_t receiver, uint64_t code, uint64_t action ) {
auto self = receiver;
if( action == N(onerror)) {
/* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission /
eosio_assert(code == N(eosio), "onerror action's are only valid from the "eosio" system account");
}
if( code == self || code == N(eosio.token) || action == N(onerror) ) {
TYPE thiscontract( self );
switch( action ) {
EOSIO_API( TYPE, MEMBERS )
}
/ does not allow destructor of thiscontract to run: eosio_exit(0); */
}
}
}
问题原因:
由于abi转发器允许下注而不将eos转移到合同中。
修改措施:
1.去掉错误判断
2.过滤传入操作 只将eosio.token的行为传入合同
提醒:
更强大的代码测试
至少两次审计
资金监控