Zilliqa ~ Smarter than the Contract: Secure Solidity Patterns and Alternatives
Ethereum Denver·Wed, Oct 9, 2019, 12:00 AM
Edison Lim of Zilliqa presents Smarter than the Contract: Secure Solidity Patterns and Alternatives
Transcript
Very good. Hello everyone. Thank you for inviting me. Well, I'm Edison and I'm responsible for applications at Zelica. I lead a team of application engineers at Zelica and we create things on the blockchain.
Zelica is a permissionless, scalable, and secure public blockchain. The reason I 'm here is because I've come from a long trip. I started writing smart contracts in Solidity. Then I went to graduate school and wrote about permissioned blockchains in my thesis at CMU. After graduate school I joined Zelica as one of the first application engineers.
When you write many of these blockchain applications, you are forced to think about security. That's why I'm here, to share some things as we go. First, a general question is whether we are truly safe today. In recent years we have seen some attacks. Then, in 2016, the DAO hack occurred, in which an attacker was able to divert $60 million by exploiting a re-entry error in a contract.
Continuing with what happened in 2017, we have the parity bar, where someone was able to remove a contract, a multiple initial portfolio, and that resulted in $300 million in cash being frozen at that time . And we're lucky that there were n't any major security attacks in 2018, but major security attacks in 2018, but are we really safe, or can we take precautions to be safer? In 2018, this comes from a research paper that was published and says that almost 34,000 contracts are vulnerable. In fact, in 2018, 3.4% of contracts remained vulnerable.
It's something we need to think about, and think about the things that will make our contracts secure and vulnerable. This will be the topic of today's agenda. I know some of you here aren't blockchain developers yet , but that's okay. I'm going to review some of the complexities of blockchain development . What makes it so different from the traditional software development we 're used to?
I will talk about some of the safety issues that arise along the way. I will present some tools and also some alternative smart contract platforms . Okay. First, . Okay.
First, what makes smart contract programming different? As someone from a traditional background, this is how we see the world. You have a server that communicates with the database and is very predictable because many simultaneous controls are controlled by your database. There is a programming system. It ensures that your transactions are completed and that you get the result you want.
Therefore, it is very easy to control. But in blockchain this gets a little more complicated, so the blockchain contains both wallets and contracts. Basically, what we think about smart contracts is that users can communicate with other contracts and that's fine, and that's still fine. But the worst part is that contracts can communicate with other contracts, and later I'll show you an example where we forget this second point where contracts can communicate with other contracts. This is where some of the mistakes occurred.
I'll share it with you later. Okay share it with you later. Okay . Okay. When we think about Ethereum, there is also one more thing: Ethereum is an infinite state machine.
And what I mean by that is that there is a starting point, which is a genesis block, but we don't actually see an end point; It will simply keep working, working, working forever. And within each block, it 's very impossible for you to determine the state of the next block the state of the next block . Therefore, in this infinite space, you need some way of thinking about development in general. Therefore, Ethereum nodes agree on a shared global state that is modified over time through transactions, and there is really no final state for this. Therefore, what really makes smart contracts so difficult to program is that they are complex.
A smart contract has to do a few things. You need to store the state. Basically, your database is all at the smart contract level . It needs to be able to perform calculations, multiplications, additions, and divisions, all within the smart contract. And it needs to be able to communicate with other contracts or other users.
For example, if you had a crowdfunding campaign and wanted to raise funds, you would ensure that your smart contracts could transfer the funds to you, and all of this would be done in a single contract. This makes it very difficult to reason about this piece of code, and this makes us a trap for attackers to exploit. Furthermore, when we think about software development, we are very used to getting what we want it to do. As developers, we're very good at telling people what our apps can do. But what we can't do is tell people what our apps can't do.
This is where things get interesting because of the way the blockchain is designed . Sometimes, your transactions may not go through, and you ca n't really control how your transactions will be placed on the blockchain. In summary, these are some of the things that contracts have to store: states contracts have to store: states , which are basically data, and they have to be able to communicate with other contracts. Transactions are not free. We need a way to calculate how gas is factored in so we can compensate the miners properly.
Furthermore, the blockchain is immutable. Therefore, once we implement a smart contract on the blockchain, you cannot change that contract. I mean, this is generally the rule of the time. Okay, let's dive into some of the security attacks. This is the most interesting one, which is the re-entry attack, and this happened in the hack.
What happened here is that there is a claims function in the DAO and what it basically does is return the money to the user. As you can see in the first line, it refers to the amount of money a taxpayer has contributed to the fund. Then, on the second line, it makes a value call, which is an unsafe method, by the way. Do not use this method to call another person to return this address, or to return this amount to another user. And finally, reset this balance to zero.
So, what the developers of this contract didn't think about is that the address on that second line is the one you 're trying to send to, it might not be a user; It could be an address, it could be a smart contract, which is basically permission for this bug because someone managed to call this function through a smart contract, allowing them to re-enter this contract and continue draining the funds, in real time. So, some people say that when you're in 2016, it's like watching a bank robbery in real time. You can see how they divert your money, but there's no way to stop it. And secondly, there is what is called a frontal attack. Some of you know it by the term transaction order dependency.
So, the idea is that you can't determine which transactions come first. So, in Ethereum, when you send a transaction and someone else sends a transaction, miners have an economic incentive to place the one with the higher gas price above the others. This way, some of the transactions could be confirmed before yours. For example, in this contract, we call a market and assume that I want to update the price. So, I want to allow it to be sold to other people.
Someone else can put a higher estimated cost so they can buy it before my transaction updates the item's price. In this case, you may obtain the item at a cost that is incorrect. This is the basis of the error. Finally, there is what is called uncontrolled resource consumption . Basically, what it does is that if you don't control the size of your array and grow it arbitrarily, you could reach a point where the cost of obtaining an item from your array could exceed the total guest limit of the block.
This is very, very problematic. And, for example, in this case, if a caller tries to empty this array needed to win this lottery, this transaction will never take place and no one will be able to call this contract because this contract, for this function itself, requires an amount of guesswork that is much greater than the block's gas limit. Therefore, this is a denial-of-service attack on the smart contract, and I believe that right now, if you use any analyzer or auditing tool, it will clearly tell you that it is vulnerable. We have seen some of these attacks. What can you do about it?
Here are some things. In the first mistake, instead of using the corn value, simply use a safe method like transfer or send. These are basically safe because they have a guess instruction for the next address that is just enough to trigger an event. Therefore, there is no way for an attacker to re-enter the contract because there is not enough gas to re-enter the previous contract. So be careful with black holes.
Here, in particular, there are some prohibited directions and this may sound stupid, but it happens this may sound stupid, but it happens . There are 800,000 ethers at address zero. If someone can find a private key to locate this zero address, you could become a millionaire. Or even in EOS, where there is like $150,000 in locked contracts, ethers locked in the contract itself; And since nobody has the private key to the contract address, it is lost forever and remains locked there forever. Therefore, if you perform an ether scan, you can still see this in the scan.
Therefore, I believe that, at a minimum, you should perform these two checks to ensure that you are not sending your tokens to a zero address or a contract address. The next thing is that this is a paradigm of thought. It's a thought process about how you should reason about the security of smart contracts: first you start with a precondition. This means you should put your require statement, your modifier, everything at the top and check if the parameters are valid. If they are valid, you can continue and make the status changes.
Finally, you interact with other smart contracts. This is how you should think about drafting Ethereum contracts and any smart contract in general. You should always put the communication last because if any contract fails, there are several reasons for it: one is that you don't know what the contract will be called, you 're not sure if this type is malicious or not. You should always assume that you are in an adverse environment and that you need to protect your interests. The fourth thing is that if you need to give money back to people, always favor pull over push.
So, in this example of a bidding auction, if you win a bit, you basically send this money back to the previous bidder with the highest bid. But what you should do instead is put it in the data structure within your contract so that someone else has to explicitly claim that money from the contract explicitly claim that money from the contract . The second one is a better way to do it. I know it's not the best experience for the developer, but it 's a safer way to refund the user. Some general advice and philosophy along the way is that you should always implement circuit breakers and speed bumps.
So, what do I mean by circuit breakers? It's basically like a fault switch. If things go wrong, it will trip this circuit breaker and may temporarily freeze transactions until you fix the problem. And the speed bumps also mean you should expect some delays. So, perhaps introducing some kind of block time, a minimum block amount before the next transaction can be made, is a very good way to think about it.
These are the two things you should think about. Simplicity is the ultimate sophistication. What I mean by this is that you should keep your contracts simple. He always prefers a modular approach to a monolithic approach. The monolithic approach means that you put all your code into one function and don't try to turn it into different functions.
Instead, you should always try to make it a modular function because it's easier to test and easier to track your error message. This is a bit primitive, but I've always found it useful to draw the state diagram on a piece of paper. And this is the reason: when you draw things, you can see them in a way that your mind doesn't really think about. For example, there is something called event ordering, and it 's basically the idea that if you send some different inputs, there can be different outputs depending on the order of this transaction. Therefore, it is the overlap of the transaction ordering dependency that I was talking about.
And what this basically does is violate this linear resizable property linear resizable property , which is basically a well-known property in concurrent data structures. Think of it this way: an operation should always appear synchronous. It should always seem instantaneous and atomic to an end user. And basically, one way to think about it in a real-life example is to imagine you have a computer with two threads and you 're trying to count; it's a global counter. So, if two of these, threads A and B, increment this counter by one, someone with a bug like this, basically the order of events, will inform them with a value of one because one of the values will precede the other and they will overwrite this call instead .
A good program will always give you two because it considers both inputs arriving simultaneously and returns the correct output of two instead of one. Okay. Okay, enough with the theory. What can you do about it ? Fortunately, Ethereum has many security tools that you can use.
One of them is that you can use visualization to visualize how your state changes over time. When we think about bug detection, we try to find different paths to a bug, and if you can't find a bug, you can rest assured that you're safe. Basically, this is a diagram to show you how the error detection approach works in general. There are many automated code auditing tools like Oriente, and I would suggest you use this tool. They should always use test coverage.
Recently, they can even be integrated with Truffle, which will integrate very well with your Travis CI2. Therefore, you should always use this and link to us. If you don't have one in your editor, install it now because it requires no effort. It will simply show you things that could go wrong. For example, things like unused parameters.
Therefore unused parameters. Therefore , always install an llinter on your machine, whether it's Solidity, JavaScript, or Python; simply install them and you can eliminate 90% of the errors that occurred. Good. These are basically the tools I explained to you earlier. You can use this tool to detect some of these errors.
The diagram on the right shows this tool called Mayan MAIN, and it was developed last year. What it can do is detect smart contracts with different kinds of security flaws, such as being greedy, prodigal, or suicidal. Therefore, it is able to detect things like the multistick wallet tag in parity. Look, if you use some of these tools, you can avoid things that happened in the past, and we can also consider an alternative smart contract language. I'm not sure how many of you in this room already use Viber, and I think Viber is very exciting.
Recently, there was a formally verified Viber contract and I'm very excited about the progress. And I really think it's a general-purpose, experimental tool, and since I'm also a Python developer, I find it much more intuitive. The idea is to create a simple and secure Spark contract , and it attempts to eliminate many of the errors found in Solidity. It's still experimental, it's still in beta, so use them with caution. Yes.
Another one that is an intermediate-level smart contract language. As a disclaimer, this is a language that was developed in my company. We believe this is a good way to think about the security of a smart contract. Basically, what happens is that we impose a structure on the developers. So yes, you don't have the freedom to do whatever you want, but we impose a structure so that, for example, things like ensuring that communication takes place at the end of the performance are applied at the language level.
So when we apply all these rules, we try to eliminate some of these potential attacks and vulnerabilities that you might face when developing your contracts. Therefore, it is a principle-based language that imposes a structure that makes your smart contract less vulnerable. Clearly separates computing from communication. Therefore computing from communication. Therefore , communication will always occur at the end, and this is done at the level of language.
This language can be modified for formal verification. We developed this language jointly with [ __ ], which is a testing assistant, and as a disclaimer, this was developed in my company. So take it with a grain of salt if it's the best tool for you or not. Yes. And since we're sponsoring this event, we're offering a $3,000 reward to any hacker interested in building a cross-chain oracle building a cross-chain oracle .
We believe the future is collaborative . We believe the future is collaborative . If you are able to build things like Ethereum, move to a centralized oracle, and then back to the Zelica blockchain, we would be happy to give you this $3,000 and would be happy to guide you. If you're interested in this, or if you're interested in Zelica in general this, or if you're interested in Zelica in general , come and talk to me later. Thank you.
Yes. Any questions? Yes. Go ahead. The reentry attack occurred in this area.
Make sure this...Yes. Yes. Well, let me explain what's going to go wrong with this explain what's going to go wrong with this . So, if you try to transfer funds to a contract, what happens if this contract address is not a user's, but a smart contract making this call?
Basically, what happens is that you are sending an if statement to a contract that will never be able to retrieve it because the contract may not have the function to transfer it to another party function to transfer it to another party . This causes the ether to be locked forever. When we think about addresses in Ethereum in general, there is always this difference between a user contract and a user address or a smart contract address . The problem with this push is that if you try to transfer an if statement to a contract, it will never be able to retrieve it, and this will cause the if statement to be frozen forever. Yes.
Does that answer your question? Brilliant. Thank you. Yes, go ahead. These slides are not public.
Yes. Well, these slides are... I'll have to think about it, but yes. Well, I'll give you my name later, so if I make it public, I'll let you know. Yes.
Any other questions? Okay, great. Thank you.
Automatic transcript — names and jargon may be misspelled.