Sandboxing Ethereum dapps with Electron
When we chose what would be our main build target for Aragon, our priorities for choosing Electron + MetaMask were security and usability.
Of course Aragon also runs on any Web3 environment (like Mist, Parity, Chrome with MetaMask...) but we wanted to have a build target in which we have full control over the user experience.
Since we got part of the community intrigued on how our implementation works, this post hopes to explain our decisions and the challenges we found.
- Dapps that execute contract code on your behalf should be packaged and their integrity verified in each release. Electron enables easy packaging for all desktop platforms.
- We need to access some system capabilities (eg Keybase).
That was what pointed us to Electron. It would give us the security and user experience control that we aim for.
- It's the easiest way to interact with Web3. A lot of people are already used to it in the ecosystem.
- No gigabyte download is needed to run it. This makes the FTUE (First Time User Experience) really smooth, as seen below.
- It's very user friendly. It still needs a lot of work on the UI/UX front, but it will progress.
- They have plans to become a light client, so AFAIK it won't need INFURA to work in the future.
Our threat model
Since we're paranoid, our threat model is that no matter if the attacker managed to get malicious code inside Aragon, it could not attack the whole operating system or the user's wallet (MetaMask).
By default Electron basically lets its contained application to execute any arbitrary NodeJS code, meaning that a successful attacker could effectively own your operating system.
We removed this attack surface by turning nodeIntegration to false, so the dapp is as sandboxed as it would be running in a normal browser.
We would run the code that requires operating system calls (eg the Keybase integration) in Electron's main process and leave the rest running in renderer processes (sandboxed).
When disabling NodeJS integration, the standard way to do IPC in Electron is gone. So we had to develop our own safe, secure IPC method, called Intertron.
MetaMask's build target are browser extensions. So how did we manage to embed a browser extension like MetaMask into our Electron app?
We had to:
- Implement a lot of dummy APIs faking Chrome's so we didn't have to distanciate a lot from their codebase.
- Replace their default communication method between the extension and the webapp (using Ports) with an isolated, inter-origin communication using postMessage.
- Implement custom protocols so Aragon is served over aragon:// and MetaMask over metamask://. This way, we enforce different origins, thus providing full context isolation (eg there's no way the Aragon dapp can access MetaMask's private keys).
- Show MetaMask when we detect a transaction that needs user input.
There is a lot of work to be done in the ecosystem to advance how we package dapps from a security and easy of use standpoint.
We want to thank the awesome team at MetaMask for their efforts, and look forward to continue working with them.
You can check out our MetaMask fork, which I hope it won't exist for long and will eventually be a part of the upstream repo 🙌
Share this article: