审计智能合约需要关注哪些内容

最近学习了CERTIK灵踪安全成都链安Trail of Bits 等公司的合约审计报告;在此做一个总结,通过学习审计报告中的关注点来尽量避免在以后的合约开发过程中踩这些坑。

虽然列出的内容很多,但是背后的逻辑与思想并没有完全了解与吃透,后续还需要继续学习与消化。

合约审计的维度

合约审计主要包括下面这些大类

  • 代码规范审计
  • 代码漏洞审计
  • 测试与验证审计
  • 业务逻辑审计

合约审计的方式

  • 形式化验证
  • 静态分析
  • 动态分析
  • 典型案例测试
  • 人工审核

代码规范审计

编译器版本安全审计

老版本的编译器可能会导致各种已知的安全问题,建议开发者在代码中指定合约代码采用最新的编译器版本,并消除编译器告警。

弃用项审计

Solidity智能合约开发语言处于快速迭代中,部分关键字已被新版本的编译器弃用,如throw、years等,为了消除其可能导致的隐患,合约开发者不应该使用当前编译器版本已弃用的关键字。

冗余代码审计

智能合约中的冗余代码会降低代码可读性,并可能需要消耗更多的gas用于合约部署,建议消除冗余代码。

SafeMath 功能审计

检查合约中是否正确使用SafeMath库内的函数进行数学运算,或者进行其他防溢出的检查。

require/assert 使用审计

Solidity使用状态恢复异常来处理错误。这种机制将会撤消对当前调用(及其所有子调用)中的状态所做的所有更改,并向调用者标记错误。函数assert和require可用于检查条件并在条件不满足时抛出异常。

  • assert函数只能用于测试内部错误,并检查非变量。

  • require函数用于确认条件有效性,例如输入变量,或合约状态变量是否满足条件,或验证外部合约调用的返回值。

gas 消耗审计

可见性规范审计

fallback 函数使用审计

代码样式

魔法数字

编译错误

代码封装

集中化

可升级性

监控

代码漏洞审计

整型溢出审计

整型溢出是很多语言都存在的安全问题,它们在智能合约中尤其危险。Solidity最多能处理256位的数字(2**256-1),最大数字增加1会溢出得到0。同样,当数字为uint类型时,0减去1会下溢得到最大数字值。溢出情况会导致不正确的结果,特别是如果其可能的结果未被预期,可能会影响程序的可靠性和安全性。

重入攻击审计

重入漏洞是最典型的智能合约漏洞,曾导致了The DAO被攻击。该漏洞原因是Solidity中的call.value()函数在被用来发送ETH的时候会消耗它接收到的所有gas,当调用call.value()函数发送ETH的逻辑顺序存在错误时,就会存在重入攻击的风险。

伪随机数生成审计

智能合约中可能会使用到随机数,在solidity下常见的是用block区块信息作为随机因子生成,但是这样使用是不安全的,区块信息是可以被矿工控制或被攻击者在交易时获取到,这类随机数在一定程度上是可预测或可碰撞的,比较典型的例子就是fomo3d的airdrop随机数可以被碰撞。

交易顺序依赖审计

在交易打包执行过程中,面对相同难度的交易时,矿工往往会选择gas费用高的优先打包,因此用户可以指定更高的gas费用,使自己的交易优先被打包执行。

拒绝服务攻击审计

拒绝服务攻击,即Denial of Service,可以使目标无法提供正常的服务。在智能合约中也会存在此类问题,由于智能合约的不可更改性,该类攻击可能使得合约永远无法恢复正常工作状态。导致智能合约拒绝服务的原因有很多种,包括在作为交易接收方时的恶意revert、代码设计缺陷导致gas耗尽等等。

函数调用权限审计

智能合约如果存在高权限功能,如:铸币、自毁、change owner等,需要对函数调用做权限限制,避免权限泄露导致的安全问题。

call/delegatecall 安全审计

Solidity中提供了call/delegatecall函数来进行函数调用,如果使用不当,会造成call注入漏洞,例如call的参数如果可控,则可以控制本合约进行越权操作或调用其他合约的危险函数

返回值安全审计

在Solidity中存在transfer()、send()、call.value()等方法中,transfer转账失败交易会回滚,而send和call.value转账失败会return false,如果未对返回做正确判断,则可能会执行到未预期的逻辑;另外在HRC20 Token的transfer/transferFrom功能实现中,也要避免转账失败returnfalse的情况,以免造成假充值漏洞。

tx.origin 使用安全审计

在智能合约的复杂调用中,tx.origin表示交易的初始创建者地址,如果使用tx.origin进行权限判断,可能会出现错误;另外,如果合约需要判断调用方是否为合约地址时则需要使用tx.origin,不能使用extcodesize。

重放攻击审计

重放攻击是指如果两份合约使用了相同的代码实现,并且身份鉴权在传参中,当用户在向一份合
约中执行一笔交易,交易信息可以被复制并且向另一份合约重放执行该笔交易。

变量覆盖审计

智能合约中存在着复杂的变量类型,例如结构体、动态数组等,如果使用不当,对其赋值后,可能导致覆盖已有状态变量的值,造成合约执行逻辑异常。

其他的攻击与安全检查的点

下面这些审计的点后续再做持续的学习与解释补充

  • 重排攻击
  • 注入攻击
  • 条件竞争攻击
  • 时间戳依赖攻击
  • 冗余的回调函数
  • 函数状态变量的显式可见性
  • 逻辑缺陷
  • 未声明的存储指针
  • 算术精度误差
  • 假充值漏洞
  • 变量覆盖
  • 设计缺陷
  • 潜在后门
  • 代币发行
  • 代理升级
  • 委托调用插槽共享
  • 用户资金安全
  • 迁移管理

测试和验证

自动化测试与验证工具:

测试和验证关注点

  • 代码自动化测试覆盖率
  • 代码测试用例通过率

业务逻辑审计

根据白皮书和被审计公司的业务逻辑进行的审计,包括:

  • 业务逻辑审计
  • 业务实现审计