DEV Community

George K
George K

Posted on

Web3-frontend security

In the web3 universe, security is of paramount importance, as a lot of money is at stake, and any mistake can lead to great losses. Too many people are in the business of looking for vulnerabilities in projects in order to exploit them. First of all, they look for vulnerabilities in contracts, thus in the market, there are companies that audit them. For some reason, the web3 universe lacks front-end auditors, even though front-end vulnerabilities can also lead to big losses. Here is an example of one of the biggest exploits — the attackers were able to steal $ 120 million.

By frontend, I mean not only the client-side, but also the server (for example nodejs), that responds to a request from the browser and acts as an intermediary between the browser and the API.

The frontend for decentralized applications does not introduce new types of vulnerabilities, but some of them may pose a greater threat specifically for web3 projects. For example, Cross-Site Request Forgery (CSRF) may seem not to pose any danger for some types of projects, however it may introduce serious risks for web3 applications.

Cross-site scripting (XSS)

Probably one of the most dangerous vulnerabilities allowing an attacker to execute arbitrary code on a page. In fact, it means getting full access to the web page: one can change its content, send requests on user behalf, read sensitive data, and so on. For example, when a user clicks on the send "transaction button", malicious actor can replace the payload of the transaction so that the user sends their funds to the attacker's wallet.

Let’s take a closer look. Imagine some app accepts search parameter in query string and renders page with text "Search results for query: ${search}". If app does not sanitize that param user can pass something like search=<script>alert(1)</script>. And that code will be executed.

User input can be anything:

  • query string or data from submitted form (e.g. UI uses some GET parameter to display it on the page);
  • user generated content - if users can generate content on the site (e.g. a comment);
  • data from localStorage, sessionStorage, cookie.

How to protect:

  • Never trust user input, always sanitize it
  • To reiterate, you can't trust any user input: query string, from data, local and session storages, cookies, IndexedDB, etc
  • Client-side frameworks usually sanitize data by default. However, React, for example does not sanitize data used in attributes (i.e. <div data-name={evilUserInput}></div> can be dangerous)
  • Correct Content-Type. An XSS vulnerability can also happen on a server without an html page. For example, the express framework defaults to text/html. And code like if (req.params.option !== "foo") { res.send(Invalid option ${req.params.option}) } leads to a vulnerability, an attacker can pass ?option=<script >alert(1)</script> and share this link
  • X-XSS-Protection: 0 header. Yes, you need to turn it off, only introduces more risks. If you want to dive into it, read more here https://stackoverflow.com/a/57802070
  • Content-Security-Policy header. Let’s discuss it in more detail.

Content-Security-Policy

With this header, you can struct browser which types of resources cannot be loaded, which can be and how. For example, you can allow .js scripts to be loaded and executed only from your domain using Content-Security-Policy: script-src self, in this case all inline scripts on the page will not be executed.

So even if an attacker can find an XSS vulnerability and insert a malicious script, the code will not be executed and users will be safe. With Content-Security-Policy, you can allow certain inline scripts if you need. More information about this header https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

Clickjacking

The main type of attack is when an attacker inserts an invisible iframe with a service on their site. And when clicking on a button, the user actually clicks a button on the service, thus performing some kind of action without realizing it.

An attacker can also do the opposite:

  • embed a service in your iframe to pretend to be the service itself;
  • place a malicious button on top of it with a “bad” transaction that will send money to the attacker;
  • it remains to somehow get the user to visit their website (e.g. by using similar domain name and sending phishing emails), the user may not notice that they are using a different website.

How to protect:

  • Header X-Frame-Options: DENY. If your service uses iframes, you can specify SAMEORIGIN or a list of domains where it is allowed to embed an iframe with the service.
  • Or you can do the same with Content-Security-Policy: frame-src self.

Cross-Site Request Forgery (CSRF)

If your site has authorization, then you may face CSRF. How it works: an attacker on their site can send a request to the your service, where the user is authorized, imperceptibly from the user. Further, they can do some action on behalf of the user.

For example, send money to someone if the service allows it. For a GET request, this is quite simple, for example, one can insert <img src=“https://mybank.com?transfer.php…” />, and send (submit) the form for a POST request.

How to protect: use CSRF tokens. The request for each user action must contain a unique token that only your service knows, thus, the attacker's site cannot access it.

Other vulnerabilities and best practices

There are other types of attacks that are less common or less likely to lead to large losses. However, it's still good for you to at least know about them and keep in mind that they exist.

  • DDoS. Use services like Cloudflare to protect from DDoS attacks.
  • CSS injection. You should protect the website from loading styles from different domains with the “Content-Security-Policy” header.
  • Referrer leakage. In case there is some sensitive data in the URL, it can be leaked when a user goes to another website. Use the “Referrer-Policy” header to instruct browsers to not send the Referrer header.
  • Open redirect.
  • Smuggling requests.
  • Npm audit. Use it to check if packages you use do not have known vulnerabilities.
  • HTTPS. Always use HTTPS protocol.
  • Do not store sensitive data client-side if possible.

Instead of conclusion

All in all, it was just an overview, I briefly touched upon the topic of front-end security. For a profound understanding of vulnerabilities and how to fix them, it is not enough. It was just to spark your professional curiosity and a springboard for further reading.

Good luck with your web3 projects, and, hopefully, this article at least made some of you think about improving your project’s frontend security.

Top comments (0)