Zilliqa ~ Smarter than the Contract: Secure Solidity Patterns and Alternatives
ETHDenver 2019 · February 2019 · 22:15
A Zilliqa-led session at ETHDenver 2019 covers secure Solidity patterns and alternatives, examining common vulnerabilities in smart contract code and design choices that help developers avoid them. The talk situates these patterns within the broader question of how different smart contract languages and platforms approach safety.
Speakers
Topics
From ETHDenver 2019, hosted by ETH Denver.
Transcript
All right, hello everyone. Thanks for having me. So, I'm Edison and I'm a application lead at Zilliqa. So, um So, I I lead a team of application engineers at Zilliqa and we build things on top of the blockchain. So, Zilliqa is a public permissionless blockchain and it's scalable and secure. And the reason why I'm here is that I so I I came from a long journey. So, I started off with a Solidity writing smart contracts on Solidity then I went on to grad school and I wrote about permission blockchains in my thesis at CMU. So, after after grad school I joined Zilliqa as one of the first application engineers. So, when you are in a capacity that you are actually writing a lot of these applications for for
blockchain, you are forced to actually think about security and this is what I'm here for is to share some things along the way. So, so first of all, just a general question is that are we really safe today? So, over the past few years we have seen some attacks. So, in 2016 there's the DAO hack in which an attacker is able to siphon away $60 million by exploiting a re-entrancy bug in the contract. Following following which in 2017 we have the parity bug where someone is able to kill a contract a multi-signature wallet and that resulted in $300 million worth of ETH at the point of time to be frozen.
And we are lucky that in 2018 there hasn't been any major security attacks, but but really is that are we truly safe or can we actually take precautions to to make it ourselves safer? So, in 2018 this is from the research paper that was published and Uh, it says that uh, one uh, nearly 24,000 uh, contracts are vulnerable. So, that's actually 3.4% of the contracts that are still vulnerable today in 2018. So, this is something that we have to think about. And um, and really think about things that would make our our our contracts safe uh, vulnerable.
So, this is going to be the agenda today. Um, I know some of you in this room might not be um, uh, a blockchain developer yet, but that's all right. So, I'll go through with you some of the intricacies of blockchain development. What makes it so different from the traditional software development that we are used to. I'll talk about some of the security pitfalls along the way. Introduce some tools and also some alternative uh, smart contract platforms. Okay, so first of all, what makes smart contract programming different? Uh, someone from traditional background, this is how we see the world. You have a server that will start to talk to the database and it is very pre- predictable. Because many concurrent controls are actually controlled by a database. There's a There's a scheduling system. It makes you it makes sure that
your your transactions come in and uh, you get output that you want. So, it's a very easy to be controlled. But on the blockchain, things gets a little bit more involved in a way that uh, your your blockchain contains both the wallets and the contracts. And um, so basically how we think about smart contracts are that the the users can talk to other contracts. And that's all right. Uh, and uh, that's that's still okay. But the worst of all is that the contracts can talk to other contracts. And later I'll show you an instance where uh, where we forgot about this fact. The second point, where contracts can talk to other contracts. So, this is where some of the bugs actually happened.
I'll show you a little on. Okay, so when we think about Ethereum, um, there's also one more thing is that Ethereum is an infinite state machine. And by by what I mean is that there is a there's a start point, which is the Genesis block, but we we We don't see an end point. It it will just keep on going, going um, going forever. And within every block, it is very impossible for you to determine what is the state of the next block. So, in this infinite space, you need some kind of a way to to think about it development in general. So, Ethereum nodes agree on a shared world state that's modified over time by transactions, and there is really no end state to this.
So, what really makes smart contract really hard to program is that it is complex. A smart contract has to do a few things. It needs to store state. Basically, your database is all in the smart contract level. It needs to be able to do computations, multiplication, addition, division, all on the smart contract. And it needs to be able to communicate with other contracts or other users. So, for example, if you were to have a crowdfunding campaign, and you want that and you managed to raise the funds. So, you are going to make sure that your smart contracts can be can transfer the funds over to you. And this is all done on one single contract.
So, this makes this piece of code really hard to reason about, and this makes us this this is why it is a honeypot for attackers to attack. And also, when we think about software development, we are very used to the world that we get whatever things that we we want them to do. So, as developers ourselves, we are we are extremely good in telling people what our applications can do. But what we cannot do is to tell people what our applications cannot do. So, this is where things get interesting because of the way that blockchain is designed, some of the sometimes your transactions might not get through, and you you can't really control how your transactions are going to be placed on the blockchain.
In summary, these are the few things is that contracts have to store states, which is basically data, and it has to contracts. Transactions are not free. We need a way about calculating how gas is being um computed so that we can compensate the miners appropriately. And also, blockchain is immutable. So, once we deploy a smart contract on a blockchain, you cannot change that contract. I mean, this this generally generally the rule of the time.
So, let's dive into some of the security attacks. So, this is the one that is the most interesting, which is the reentrancy attack. And this happened in the DAO hack. So, what happened in here is that there's a reclaim function in the DAO. And what it basically basically does is that it returns the money back to the user. So, as you can tell in this in the first line is that it reference the amount of money that a contributor has contributed to the fund. Then in the in the second second line, it do a call the value, which is a unsafe method by the way. Please do not use this method to call another to to return this address to to return this amount to another user.
And finally, it resets this balance back to zero. So, what the developers of this contract did not think about is that the address in that second line is that um that the one that you are trying to send to, it could it could be not a user. It could be an address. It can be a smart contract, which is basically the the promise of this bug. Because someone managed to call this function through a smart contract, which will allow it to reenter this contract and keep draining the funds in real time.
So, some of the people say that when you're in 2016, you're like looking at a bank robbery in real time. You can see a money being siphoned away, but there's no way for you to stop this. And secondly is about this thing called a front running attack. So, some of you known this by by this term called transaction ordering dependence. The the idea is this is that you are you are not able to to determine which transactions go first. So um So how it works in Ethereum is that when you submit a transaction and someone else submit a transaction, the miners have an economic incentive to place the one with a higher higher gas price above the others. So in this way, some of the
transactions might get confirmed before your transaction. So for example, in this contract called marketplace presume that I want to update the price that I want to allow it to be sold to to people. Someone else can actually put a higher gas cost so that they can buy it before my transaction to update the price of the item gets through. So in this case, he's able to get the item at a at a cost that that that is incorrect. So this is the this is the basis of the error. Finally, there's this thing called an uncontrolled resource consumption. And what it basically does is that if you don't control the size of the size of the array
and and you grow it arbitrarily, you might reach the point to a point that the cost of fetching an item from the array might exceed the whole gas limit of the block. And and this is very very problematic and So in this case, for example, that if a caller tries to empty this array and then to shred this lottery this this transaction will never go through and no one is able to call this contract. Because this contract this for this function itself, it requires a gas amount that is way higher than the gas limit of the of the block. So this is a in fact DOC it's a denial of service attack on the on the on the smart contract. And I think that right now if you use any
analyzers or any auditing tools, they will flag this out to you to say that this is a vulnerable. So uh so we have seen some of this attacks. So, what can you do about it? So, here are some things. So, uh on the first bug just now, instead of using call.value, simply use a safe method like transfer or send. These are These are These are basically safe because it because it has a it has a gas stipend for the for the next address, which is only sufficient for it to emit an event. So, there's no way that an attacker can re-enter the contract because there's not enough gas to re-enter the the the preceding contract.
So, uh be careful of black holes. So, particularly in in here and there are a few no-go addresses, and this might sound stupid, but it happens. So, uh there are 800k worth of ethers in in the zero address. If someone can find a private key to find this zero address, you might get you might be a millionaire. Uh even in EOS, where there's like $150,000 uh worth of contract stuck uh worth of ethers stuck in the contract itself. And because no one has the private key to the contract address, the ether is just lost forever. And um it's just locked up there forever. So, if you go to Etherscan, you can still see this on the Etherscan.
So, I think at the minimum, you should do these two checks to make sure that you're not sending uh your tokens to a zero address or a contract address. Uh next is that it This is a This is a paradigm of thought. It's a It's a thinking process of how you should reason about smart contract security. Is that you first begin with a precondition. So, this means that you should put your require your require statement, your modifier, all at the top, and check whether the parameters the parameters are valid. So, if they are valid, then you may go on and make the state changes.
Finally, uh then you interact with other smart contracts. So, this should be how you think about uh writing writing Ethereum contracts and any smart contract in general. You should always place communication at the last. Because if if any contract fail and I mean there's there's a few reasons to that. One is that you do not know what your contract is going to call. Like you're not sure if this guy is malicious or not. You should always assume that you're in an adversarial environment and you need to make you need you need to protect your interest.
So the first thing is that so if you need to return money to people, always favor pull over push. So in this example on a on a bad auction is that if you win a bid and you basically sent this money back to the previous highest bid highest bidder. But what you should do instead is that you should place it in a data structure within your contract such that someone else has to has to explicitly claim that money back from the contract. So the second one is a better way to do it.
I know it's not a very ideal for developer experience but it is a safer way to go about returning money back to the user. And some general tips and philosophy on the way is that you should always implement circuit breakers and speed bumps. So what do I mean by circuit breakers is is basically like a fuel switch. If things if things go wrong then it then it will go into this circuit breaker and it can temporarily freeze transactions until you fix the issue. And also speed bumps is that you should have some delays. So maybe introducing some kind of block time some some minimum amount of block before the next transaction can go through is a is a very good way to think about it. So these are the two things that you should
think about. Simplicity is the ultimate sophistication. So what I mean by this is that keep your contracts simple. Always prefer modular approach to money related approach. So the money related approach means that you put all your code into one function and you don't try to make them into different functions. Instead, you should always try to make it into modular function because it is easier to to test and it's easier to trace on your error message. Uh and this is a bit primitive, but I always found it helpful to draw the state diagram uh on a on a piece of paper. Uh and and this is why is that when you draw out things, you can see things in a way that uh your mind don't really think about. Uh so for example,
this there's this thing called an event ordering uh about. And basically, it is that it is the idea that uh if you send a few different inputs, um there might be different output based on the order of this transaction. So it is the superclass of the transaction ordering dependence that I was talking to you about. And uh what this bug basically does is that it violates this property of um linear linearizability, which is basically a well-known property in concurrent data structures. So think about it this way is that an operation should always seem to be uh synchronous uh it should always seem to be instantaneous and atomic to a to end Uh and um
and basically, so one way to to think about it in real life example is that imagine you have a computer with two threads and they are trying to count uh it's a it's a global counter. So if two of these threads, A and B, uh increase this counter by one, uh so someone with a bug like this uh basically event ordering is that it will report you with a one uh value of one because it because one of the values will precede the other one and you will overwrite this call. Instead, a good program will always give you two because it considers both of these inputs that are coming in simultaneously and it returns you the correct output of two instead of one.
Uh okay, so um so enough of theory. So what what can you do about it? And uh fortunately for Ethereum, there's a lot of security security tools that you can use. So, one of them is that you can actually use visualizations to visualize how your state changes over time. So, when we think about bug findings, it's about you trying to find different path to an error. And if you can't find an error, you can you can be sure that you're safe. So, this is basically a diagram to show you how bug finding approach works in in general. And there's a lot of these automatic code auditing tools like Oyente and Mythril. I I would suggest that you guys use these tools.
You should always use test coverage. Recently, that you can even integrate them with Truffle, which will integrate it nicely with your Travis CI tool. So, you should always use this. And linters, if you don't have one on your editor, install it now because this takes no effort at all. You You will just simply show you things that that might go wrong. For example, things like unused parameters. So, always install a linter on your machine. Whether it's a Solidity or is it JavaScript or is it Python, just install them and you're and you will be able to eliminate 90% of the bugs that will happen.
Okay, so and this are basically the the tools that I've I've explained to you previously. You can use these tools to actually detect some of these errors. So, in the diagram on the right side is this tool called Maian, m a i a n, and it is a tool that was developed last year. So, what it is able to do is that it's able to detect smart contracts with different classes of security flaws like being greedy or being prodigal or being suicidal. So, it is able to detect things like the the multi-sig wallet hack in the in the Parity. See, so so, if you use some of these tools, you can avoid things that happened in the
past. And uh we can also consider alternative smart contract language. So, I'm not sure how many of you in this room are already using Viper. And I think that Viper is really exciting. Recently, there's a formally verified Viper contract, and I'm really excited for the progress. And um I really think that it's a general purpose uh experimental uh and uh because I also I'm a I'm also Python developer, so it seems a lot more intuitive to me as well. And the idea is to build a simple and secure smart contract. And it tries to eliminate uh many of the bugs that are found on Solidity.
Um it is still experimental. It is still beta. Still uh so so use them with a precaution. Yep. Another one that is a smart contract intermediate level language. So, as a disclaimer, this is a language that was developed developed in my company. So, uh we believe that this is a quite a good way to think about security of a smart contract. Basically, what happens is that we impose a structure on on developers. So, yes, you're you're not they're free to do whatever you want. But but we impose a structure such that, for example, this like making sure communication happen at the last of the function is enforced on a language level. So, we when we do all all of these rules, we try to eliminate some of these possible attacks and
vulnerabilities uh that you might face when you're developing your your So, it is a principal language that imposes a structure that makes your smart contract less vulnerable. Uh it clearly separates between compilation and communication. So, uh communication will always happen at the last, and this is done on a language level. This language is amenable to formal verification. We have developed this language hand-in-hand together with Coq, which is a proof assistant. And um as a disclaimer, this is developed in my company. So, uh think of your personal thought whether is it the best tool for you or not.
Yep. And uh so, because we are sponsoring this event, we are giving out a bounty of like $3,000 for any hackers who is interested to build a cross chain oracle. So we believe that the future is collaborative. So if you are able to build things between like Ethereum and going to a centralized oracle and going back to Zilliqa blockchain, we are happy to give you this $3,000 and we'll be happy to guide you along. So if you're interested in this or if you're interested in Zilliqa in general, come and speak to me afterwards. Thank you.
Yep. So any questions? Yep, go ahead. The The The re-entrancy attack you mean? This one? Yeah yeah so So let me explain what what
will go wrong with this. So if if you're trying to push a funds to a contract and what if like what if like this this contract address what what if this address is not a user, it is it is a smart contract that's making this call. And so what basically happens is that you are sending ETH to a contract that is never able to reclaim that ETH back because the contract might not have the function to actually transfer the ETH to someone else and um this results in the ETH being locked up forever. So, when we think about addresses in in Ethereum in general, there's always this this difference between a user contract
a user address or a smart contract address. So, the the problem in the in this push one is that if you're trying to push ETH to a contract, it can it can never retreat retrieve this ETH back and this results in ETH being frozen forever. So, does that clarify your question? Great. Thanks. Yeah, go ahead. Uh these slides are not public. Yeah. Uh these slides are Um I'll have to think about it, but yeah, so I'll give you my name card later. So, if I make it public, I'll let you know. Yep.
Any other questions? Okay, great. Thank you.