安全问题

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的行为传入合同

提醒:
更强大的代码测试
至少两次审计
资金监控