下面是一段网上论坛寻求解答的一个提问,也正是我们今天要讲的典型的以太币被盗场景。
1、前一天晚上,我们用本地代码去连接某云以太坊节点(公链)服务器做交易,私钥文件(A地址)保存在服务器上,交易时,失败了,到etherscan查交易时发现以太币被转到一个不认识的地址(H地址),这时尚未意识到被盗,怀疑代码存在问题。
2、第二天,往A地址转了点以太币,然后在服务器上的命令行做交易,命令行查询帐户以太币正常,解锁帐户后,交易失败,到etherscan查交易时发现以太币被转到昨天的地址(H地址),pending。
3、我们分析可能是私钥泄漏、密码简单,于是在服务器上新创建了一个地址(B地址),密码变复杂了,又转了点以太币,更新的了以太坊客户端(从1.7.3更新到1.8.1),同样在服务器上的命令行做交易,命令行查询帐户以太币正常,解锁帐户后,交易又失败了,查得以太币被转走(H地址),pending。
4、这次分析可能是服务器感染病毒,于是格式化服务器,重新搭建环境,创建帐户,转以太币,还是在命令行做交易,又发生了同样的问题,以太币被转走(K地址),pending 这到底是什么问题,哪位大神遇到过,帮忙解答下,小弟不胜感激!!!
看到这里很多掉进此坑的朋友可能已经知道了被盗的原因,现在我们就分析一下,让后来者避免再重蹈覆辙。
其实,这个问题的原因很简单,问题就出在以太坊的转账时的解锁机制。很明显,这位同学的以太坊节点是可以公网访问,没有限制入网ip。我们都知道,当发起转账交易时是需要进行解锁,看一下解锁的代码:
func (s *PrivateAccountAPI) UnlockAccount(addr common.Address, password string, duration *uint64) (bool, error) {
const max = uint64(time.Duration(math.MaxInt64) / time.Second)
var d time.Duration
if duration == nil {
d = 300 * time.Second
} else if *duration > max {
return false, errors.New("unlock duration too large")
} else {
d = time.Duration(*duration) * time.Second
}
err := fetchKeystore(s.am).TimedUnlock(accounts.Account{Address: addr}, password, d)
return err == nil, err
}
通过源代码我们可以看到,如果没有传递解锁时间参数,系统会默认将发起交易的账号解锁300秒。而以太币被盗就发生在这恐怖的300秒,在没有一点安全防护的节点服务器,这意味着在5分钟内,任何人都可以调用转账方法将此账户的以太币转到其他账户。黑客通过工具监听到某个地址被解锁,马上就调用该服务的该地址出高价手续费将余额全部转走。
以上就是新手常见的被盗场景之一,或许你还正在疑惑为什么我发出交易的时候代码报转账手续费不足,而在这之前你的以太币已经不翼而飞。针对这个问题最简单的防护措施就是确保服务器的访问限制。至于更高级的安全防护新手很难做的,也是一个很大的课题,后面的文章中会陆续讲解。