本文作者分享了智能合约安全审计的经验模型,强调了资源收集、智能合约概览、手动代码审查、功能测试、自动化审查、报告编写和修复代码审查等关键步骤。文章旨在帮助审计人员系统性地进行安全审计,并识别潜在的安全漏洞。
请持续关注关于区块链桥中常见漏洞、我的审计思维模型以及更多内容的资源 ✨🔒
本文档不是漏洞的检查清单,而是一个用于处理智能合约安全审计的结构化思维模型。 随着时间的推移,我发现坚持这个框架会产生一致的结果,无论是在识别细微的错误,还是在培养对代码库健壮性的更高程度的信心方面。
当以有意识的深度应用时,它是最有效的。
随着我改进我的工作流程并整合新的想法,这个思维模型将继续发展。
测试用例很重要。 它可以让你了解设置是如何进行的,用户需要处于什么状态才能开始使用系统的入口点。 此外,它还可以让你有时间测试更多的攻击性场景(在单元测试验证之后),而不是将大部分时间用于测试一般场景。
x/totalStakedEth
的值是多少。 或者在调用之后它变成了什么。已过时
的示例文章在这里)、Tenderly 调试器(示例文章在这里)。这可以通过查看图表和当前对智能合约功能的理解来完成。 例如,在这种情况下,Token 合约的依赖性最小(事实上,该合约中的功能正在其他合约中使用,因此其他智能合约依赖于它)。 它用蓝色虚线高亮显示。
从安全角度来看,访问智能合约中的所有路径至关重要。 例如,在下面的 withdraw()
示例中,每个路径都有其自身的潜在安全影响和需要验证的行为。 有时,这些意想不到的路径会将我们引向潜在的错误。
自动化的测试方法,比如模糊测试和形式化验证在这里会很有用。
正如在下面能看到的,一切都归结于每个路径。 即使是三元表达式显然也是路径。
// 它可能缺乏一般含义,但旨在演示具有多个执行路径的代码。
function withdraw(uint256 amount, bool emergency) public {
require(amount > 0, "Withdraw amount must be greater than 0");
uint256 balance = balances[msg.sender];
bool success;
if (emergency) {
success = (address(this).balance >= amount) ? payable(msg.sender).send(amount) : false;
} else {
if (balance >= amount) {
balances[msg.sender] -= amount;
totalBalance -= amount;
success = payable(msg.sender).send(amount);
} else {
success = false;
}
}
if (!success) {
// 调用其他合约来处理失败的提款
}
emit Withdrawn(msg.sender, amount, success);
}
下面的第二个例子展示了每个值都是动态的
因为每个值(_amount
,minRequired
)都可以高于和低于,结果可能会有所不同。 如果该结果用于一些操作,例如减少 burnFuelAndReduce()
中的 drivingScore
。
例如,取决于金额是否相同(与加注Gas时一样)或增加或减少,fuelReduction
的值将发生变化,并且在从 drivingScore[msg.sender]
中减去它时,需要相应地处理,这也会创建不同的路径。
如果你能看到,那就是真正的混乱!
function fillFuelAndCalculate(uint256 _amount) public {
require(_amount > minRequired, "ERR");
fuelTank[msg.sender] += _amount;
drivingScore[msg.sender] += (_amount * multiplier) / minRequired;
}
function burnFuelAndReduce(uint256 _amount) public {
fuelTank[msg.sender] -= _amount;
uint256 fuelReduction = (_amount * multiplier) / minRequired;
drivingScore[msg.sender] = drivingScore[msg.sender] > fuelReduction ? drivingScore[msg.sender] - fuelReduction : 0;
}
我喜欢写下疑问、想法、可能的问题的原因之一是,当你开始浏览这些问题时,当你遇到新路径时,你可以看到更多的疑问,你脑海中可能出现的问题。 因此,有时它会变成一个循环,在其中你会在探索之前/当前的想法时不断思考新的想法。 这就是为什么我认为最好将这些东西记录下来,这样你才不会在混乱中忘记它们。
## 项目名称
### 范围:
GH链接:
Commit 哈希值:
### 流程:
1. 手动审查
2. 功能测试:
- 单元测试
- 边缘情况测试
3. 自动化测试:
- ...
4. ...
### 资源:
1. 规范文档:
2. 白皮书:
3. 任何其他文档和链接。
### 待办事项:
*需要做的事情/剩余事情。*
1. 关于审计的高层次事项
2. 开发者项目演练。
3. ...
### 常见/疑问/研究:
1. 重新学习正在使用的特定跨链服务/协议。
### ContractName.sol
*这包含关于 ContractName.sol 的疑问/要点/研究/潜在错误*
1. 确认的问题 1。
2. 确认的问题 2。
### 疑问/研究:
1. 检查特定公式。
2. 检查特定疑问。
3. 检查 L453 上的减法可能是一个问题。
* 测试用例:
1. [test] 用户应该能够质押。
2. [test] 多个用户应该能够质押。
3. [test] ...
### ContractName2.sol
*这包含关于 ContractName2.sol 的疑问/要点/研究/潜在错误*
...
---
### 给开发者的问题:
1. 公式的解释。
2. 关于预期逻辑的问题。
3. ...
在与团队合作时,单独处理每个合约会产生更好的结果。 它还可以帮助你从整个项目的角度进行思考。 这种方法可以是协作式的,在其中可以进行大量的头脑风暴,然后在最后分享发现。 你可以看到许多优秀的团队都在遵循这种结构。
有时审计可能是一个非常并行/实时的过程。 例如,你脑海中刚刚出现了一些东西,你很兴奋地去浏览它等等。
- 原文链接: calibersec.com/smart-con...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!