Easing the access to Blockchain applications

Leandro Dardick
SOUTHWORKS
Published in
7 min readMay 20, 2021

With the rise of the dApps (decentralized applications), more and more casual and non-tech-savvy users made their entrance to the Blockchain world.

Technical users can make their own way to securely store their keys, but others user may not find that easy. Even though there are a lot of tutorials over the Internet showing how to get started, doing that without minimally knowing the technology behind, and being that the user will store valuable asset like tokens opens the window for shady things.

At the same time, many alternative Blockchain Networks such as BSC (Binance Smart Chain) gained popularity as they solved some of the problems with the original networks, such as the high gas money cost required and scalability issues. But this also added the need of extra configuration steps to access those networks.

The question right now is: How could we help those users to enter the world of dApps at the same time of granting them a secure experience?

Based on some publicly-released papers we decided to implement a Secure Hosted Wallet service with the goal of granting:

  • Seamless Wallet creation.
  • Secure keys storage.
  • Two-Factor-Authentication (2FA) ensuring that even if the service got compromised, the attackers would access worthless information.
  • Zero configuration needed from the user.

The architecture

The architecture of our solution consists on the following components:

  • An RPC endpoint granting access to the network.
  • An API that will act as mediator between the UI and the network.
  • An identity provider that will be used to allow the users authenticate and store their profiles.
  • A secure storage that will be used to store the secrets.
  • A Single Page Application (SPA) that will be used by the user to interact.
  • A Smart Contract deployed on the Ethereum network.
Solution architecture diagram

In our case, as we already had Single Page Application (SPA) using Typescript, we decided to use the same language in all the other components to be able to use the same set of tools (Ethers, Web3) across the codebase at the same time of providing a seamless transition for our developers.

To enhance security, all communication between the UI and the API is encrypted and authenticated and ensuring that only the users of our applications are allowed to consume the API and all the secrets are secure.

The Identity Provider

To ensure an optimal user experience, we were sure that one of the requirements that our solution should made is allowing the user to authenticate using the method of his choice. For this, we decided to use an Identity Provider.

An Identity Provider is a Customer Identity Access Management (CIAM) solution capable of storing the profile for millions users and taking care of the authentication.

As we were using Azure in our solution, we decided to go with Azure B2C, but there are many other alternatives and most of the cloud vendors have their own (e.g., Cognito on AWS).

Those services will allow the users to register a local account or use their preferred social or enterprise identities to get single sign-on access to the applications. At the same time, they allow the developers have full control of the information that is stored for every user.

Based on that, we decided to extend the User profile by adding the user wallet’s public address, which allowed us to match the address with the user, and at the same time validate the transaction’s sender to prevent hijacking.

Secrets Vault

Being that the Users profile is essentially public or at least accessible for anyone with administrative rights, the next question that raises is where to store the secrets for the user wallet.

To do this, we decided to delegate the responsibility to a Secure Key Vault service, that granted us industry-standard encryption to safeguard the user’s secrets. Once again, as we were working with Azure, we decided to use Azure KeyVault for that, but this service could also be replaced with other cloud provider’s alternatives (e.g., AWS HSM)

An Overview of the solution

Based on the Hardware Wallet signing process, we designed three flows that will let the user interact with the network securely without worrying about the wallet.

  1. The Wallet Creation flow
  2. The wallet decryption/unlocking flow
  3. The secure transaction signing flow

Wallet Creation flow

During this flow, the user will create the Wallet to be used to interact with the network.

To generate the Wallet, we used the method createRandom of the Ethers library. What’s really interesting about this method is that allowed us to supply extra entropy to stir into the random source increasing the security. For example, we could create entropy by asking the user to move the mouse randomly for a fixed time.

As a premise, we decided that the Private Key should never be sent to the server to ensure that, even if the application got compromised, the attackers would not be able to do anything, but, at the same time, we wanted to make the process of keeping it secure easy for the user.

Based on that, we decided to use Keystore JSON, an industry-standard representation the wallet to store it. Using this, the user will encrypt the wallet by entering an encryption password at the wallet creation time, and the encrypted representation will be stored in a secure storage. As this process is made on the UI, strength requirements can be implemented to ensure that brute-force attacks are not viable and, to be able to do anything, any attacker would need to have access to both components (The Keystore JSON and the user’s encryption password).

In a later step, the user will retrieve the Keystore and decrypt it using the same password supplied upon creation.

Wallet creation flow

As a summary, during this stage:

  1. The user will open the dApp UI and sign up in the Identity Provider by using their preferred method.
  2. A user profile will be created in the Identity Provider.
  3. The user will be redirected to a page where he will create his Wallet. The wallet is created at client-side and the private key is never sent to the server.
  4. The user will encrypt the Wallet by entering a password that will work as a second authentication factor.
  5. Once the wallet is encrypted, it will be sent to the API to be stored in a secure vault.

Wallet Decryption / Unlocking Flow

In this Flow, the user will retrieve the Keystore from the secure storage and decrypt it. Given that the encryption key is never sent to the server, the User is responsible of storing it (or remembering it) securely.

Wallet Decryption / unlocking flow

During this flow, the user will:

  1. Sign In in the Identity Provider.
  2. Retrieve the Keystore JSON from the secure storage.
  3. Decrypt the wallet by entering the same password used at creation to decrypt the wallet.

Secure Transaction Signing Flow

In this Flow, the user will use the previously created Wallet to sign transactions. To do it, we based our design on the Hardware Wallet signing process, where the transaction is prepared and then signed in separate steps.

Secure transaction signing flow

During this stage:

  1. The user will perform an action in the UI.
  2. The UI will call the API to prepare a transaction.
  3. The API will calculate the Transaction Gas Cost and the Gas Price as well as the nonce for the source address and return an unsigned transaction.
  4. The user will sign the transaction using his wallet and send the signed transaction back to the API.
  5. The API will use the RPC provider to send the transaction to the network.

Events

In any blockchain, the transactions being emitted are put in the mempool to be later included in a block by one of the nodes. Because of that, the only way of knowing when a transaction was included (if included!) in the Blockchain is by listening to Events.

This is easy-peasy if using a Browser Wallet as it exposes a Web3 provider connected to the network, but, in the case of our solution, the API is the only component with direct access to the network through the RPC endpoint.

To workaround this, we implemented a WebSocket server on the API that will listen to events in the network and broadcast them to the connected clients.

Conclusion

In this article, we showed how could we improve the user experience by hiding part of the complexity needed to connect to the Blockchain.

Enhancing the user experience at the same time of not resigning security in exchange is a difficult balance. Using a three steps process and not sending the passphrase that is used by the user to encrypt his wallet to the server, we are adding an extra security layer at the lowest possible cost in terms of UX.

--

--