Smart contract security issues: what are smart contract vulnerabilities and how to protect
When starting smart contract development, many programmers believe that learning Solidity takes less than two weeks, especially if they know JavaScript.
Though Solidity is rather simple, companies that specialize in ensuring the security of smart contracts, ask for huge money for smart contract audit.
Sometimes even large corporations and experienced developers make mistakes resulting in losses of millions of dollars. You’ve probably heard of the DAO when the attacker took away $50 million. So, why does it happen? What vulnerabilities may smart contracts have?
While in a recent post, we’ve written about smart contract audit best practices, in this article, we’ll consider bugs of Ethereum smart contracts and ways to provide the highest protection. Let’s start.
Smart contract vulnerabilities
Transaction Ordering Dependence (TOD)
In Ethereum Blockchain network, miners control the order of transactions, meaning that your transaction can be outrun by paying more gas in the other one (the higher the amount of gas, the higher the priority of your transaction for a miner is).
Only the miner who closes the block decides the transaction order, and this is the vulnerability, called transaction ordering dependence.
In TOD, you may face unexpected malicious behavior from miners. Imagine, for instance, a smart contract offering a fee (a certain amount of money) for providing the right solution to some task. The contract owner can update the prize as long as it hasn’t been claimed, and users can submit their solutions to the task to get the fee.
However, the owner can track all incoming submissions and manage the ordering of transactions. For example, when there is an unprocessed user transaction with a valid submission, the miner has the ability to check it out and then submit his own transaction thus reducing the value (the amount of fee) to zero. In case his submission will be processed first, the user’s one won’t bring any fee.
Timestamp Dependence
Unfortunately, the timestamp can be manipulated by the miner who isn’t always a user’s friend. The miner can adjust the timestamp provided by a few seconds, thus changing the output of the contract to his own benefit.
It can work as follows: when a smart contract uses the timestamp in order to generate random numbers, the miner can post a timestamp within 30 seconds of the block being validated, enabling to predict a more preferred option to his chances in this roulette.
As a user transaction is kept in the storage for a spell, the miner can find out what actions will occur, before the transaction is included in the block. This vulnerability can be a real problem for decentralized markets, where a transaction to purchase tokens can be viewed.
Hence, miners can manage timestamps:
- Miners can change the timestamp of the block:
-
– within 30 seconds
-
– the timestamp shouldn’t be less than the timestamp of the previous block;
- If the prize for the solution to a puzzle or some task, winnings is quite valuable, the chances for miners’ misbehavior increase.
There are several important considerations related to a 30-second rule:
- If the smart contract function can tolerate a 30-second time period, it’s safe to use timestamp;
- If the scale of a time-dependent event can vary by 30 seconds and maintain integrity, it’s also safe to use a block timestamp.
Reentrancy
The first version of reentrancy vulnerability involved functions which could be repeatedly called before the first function call was ended. For this reason, different function calls could interact in destructive ways. Take a look at the code below:
// INSECURE
mapping (address => uint) private userBalances;
function withdrawBalance() public {
uint amountToWithdraw = userBalances[msg.sender];
if (!(msg.sender.call.value(amountToWithdraw)())) { throw; } // At this point, the caller’s code is executed, and can call withdrawBalance again
userBalances[msg.sender] = 0;
}
Here you can see, that as the balance isn’t set to zero until the very end of the function, the later calls will still succeed and withdraw the balance over and over again. A very similar smart contract vulnerability was one of the bugs in the DAO attack.
A simple explanation to this bug was described in a Reddit comment to the DAO in 2016:
“It’s like the bank teller doesn’t change user balance until she has given you all the money you requested. “Can I withdraw $500? Wait, before that, can I withdraw $500?”
Forcing ether to a contract
Ethereum smart contracts have two main peculiarities. First, they have a self-destruct function, a Solidity function that destroys contract. The second one is payable, a modificator allowing to receive ether on the contract.
A self-destruct function does two things:
- makes a smart contract useless, successfully deleting the bytecode at the target address;
- sends all the funds of the contract to that address.
One should note, that if the receiving address represents a contract, its fallback function won’t be executed. Thus, in case a function has a conditional statement depending on the balance of this contract (which is below the necessary amount), you can bypass this statement in the following way:
contract ForceEther {
bool youWin = false;
function onlyNonZeroBalance() {
require(this.balance > 0);
youWin = true;
}
// throw if any ether is received
function() payable {
revert();
}
DoS with Block Gas Limit
In some cases you may face the following risks: by paying out to everyone at once, there is a probability of achieving the block gas limit.
Remember that Ethereum Blockchain network can process only a certain computation amount, so if you exceed it, your transaction will definitely fail. In this case, some problems may arise even if there is no an intentional attack and gas manipulation by the attacker.
What you can do to ensure smart contract security
When developing Ethereum smart contracts, the most important thing is to provide their complete security and protection. Otherwise, you may suffer huge losses like it was with the DAO, Parity, and many other projects.
The main tips for ensuring smart contract security are:
- Don’t write bad smart contract code 🙂
- Prepare as many unit tests as possible
- Focus on smart contract audit
- Use well-audited smart contract code
- Make sure that experienced developers build your project (in other cases, the code of junior should be carefully reviewed by expertise engineers)
- Use security tools
Security tools you can use for providing smart contract security
- Oyente – this written in Python tool analyzes Ethereum code to check it for common vulnerabilities (transaction ordering dependence, timestamp dependence, etc.). Uses its own symbolic execution engine.
- Solgraph – this tool generates a DOT graph allowing to visualize the function control flow for Solidity contract security analysis and define potential security bugs and vulnerabilities.
- Manticore – a dynamic binary security analysis tool providing symbolic execution engine as well as EVM support. The runtime environment supports several contracts and transactions. Also, the tool enables to start contract execution with character buffers.
- Mythrill – the tool for security analysis of smart contracts that uses a symbolic execution engine laser-ethereum.
- Hydra – represents a framework for cryptoeconomic smart contract security.
- Porosity – a decompiler and smart contract security analysis tool.
- Remix – is a static analysis tool, that can spot bugs like reentrancy.
- Securify.ch – is a static smart contract security analysis tool that checks contracts for critical code vulnerabilities and insecure code places.
- Solint – another tool providing a linting utility for Ethereum smart contracts and helping developers enforce conventions and avoid errors in their smart contracts.
Hope, the article has been useful to you.) If you have some questions about the post or a project idea, or need to audit your code, feel free to apply to us and get a free consultation!
Having high expertise in Blockchain development and delivering many successful Ethereum projects, we are ready to help you!