title: "DApp Frontend Security" summary: "Security is not just a consideration for DApp Backend Developers, but for Frontend Developers too. In this article we'll cover a comprehensive security strategy for DApp Frontends." author: robin_percy categories: - tutorials layout: blog-post image: '/assets/images/web3-article-header.png' --- ![Web3.js](/assets/images/web3-article-header.png) ## Introduction *This article is the second in my series of articles based on the frontend of the decentralised web. We'll look at [Web3.js](/news/2019/12/09/web3-what-are-your-options/) & accessing the Ethereum Blockchain client-side, [frontend security for DApps](/news/2020/01/30/dapp-frontend-security/), how WebAssembly has become the "4th language of the web", and we'll build a realtime Blockchain explorer app with Phoenix LiveView!* Working for a [security-focused company like Status](https://status.im/security/) means that security, in its many forms, is mentioned on a daily basis. However; outside of [Status](http://status.im) one of the broadest, most important, yet often ignored considerations when deploying and running web applications is the security of the app. When I use the term _security_, I’m not just speaking from a backend perspective, but also of the frontend of the application. Having good infrastructure security is highly important, but there are also security factors on the frontend of the application that we really _must_ take into account. Security is an ongoing, and ever-changing, practice that you must observe to ensure that your product is never included in the companies that one hears about on the news after a huge data breach. Regardless of which programming paradigm, language or framework you wish to use, there are plenty of non-specific, terse security practices you should follow from the very start of the project. In my last personal Startup, we provided User Authentication as a Service, so we were a major target for hackers. On one of our first evenings live, we watched someone attempt to send 5million malicious requests within 30 minutes. None of which had any affect other than exposing the hacker. This is because we made security a priority — which is something we all need to do in the modern world of Tech. In this article, I'll introduce you to my biggest tips for top to bottom (Frontend to Backend) security for your web applications. We'll take a look at security for your DApps too! ## Strict Transport Security (HSTS) HSTS is a security header that allows us to enforce HTTPS across our entire DApp. If you read my previous article, you'll remember I advocate the idea of HTTPS everywhere, and showed you how to get a trusted, secure SSL certificate free-of-charge from [Let's Encrypt](https://letsencrypt.org). The reason we need HTTPS everywhere is that our users are vulnerable to Cookie stealing and Man-in-the-middle attacks if we don't have it implemented. Now, as you're probably aware, simply owning an SSL Cert will *not* immediately make all of your DApp HTTPS only - we need to tell our App to do that, ourselves. One of the best ways of doing this is by using the HTTP Header of HSTS. By using this Header, we can force all traffic on our App to use HTTPS and upgrade non-HTTPS. This Header may also even provide a performance ***boost***, as we no longer would have to send our users through a manual redirect. So, you're probably thinking "Wow! I need this!". Well, whilst I agree - alongside the *Content Security Policy* I'll talk about later, this needs to be implemented **with caution.** Allow me to explain! Here's what a sample HSTS Header looks like: Strict-Transport-Security: max-age=630720; includeSubDomains; preload *And in Node.js:* ```js function requestHandler(req, res) { res.setHeader('Strict-Transport-Security', 'max-age=630720; includeSubDomains; preload'); } ``` In this Header, we have 3 *directives* that apply. `max-age`, `includeSubDomains` and `preload`. ***max-age***: By specifying a max-age, we are telling the user's browser to cache the fact that we use only HTTPS. This means that if the user tries to visit a non-HTTPS version of the site, their browser will be automatically redirected to the HTTPS site, *before* it even sends a message to the Server. Therein lies the slight performance boost I mentioned earlier. Now, while this *does* sound fantastic in theory, what we need to be aware of here, is the fact that if a user ever *needed* to access a non-HTTPS page, their browser simply won't let them, until this `max-age` expires. If you are going to activate this feature, and set a long `max-age`, (required by the pre-load sites I'll talk about in a second), you ***really*** need to be sure that you have your SSL cert setup correctly, and HTTPS enabled on *all* of your DApp before you take action! ***includeSubDomains***: The `includeSubDomains` directive does exactly what it says on-the-tin. It simply offers additional protection by enforcing the policy across your subdomains too. This is useful if you run a DApp that sets Cookies from one section (perhaps a gaming section), to another section (perhaps a profile section), that need to be kept secure. Again, the issue with this lies similarly to the above, in that you ***must*** be sure *every* subdomain you own and run, is entirely ready for this to be applied. ***preload***: The most dangerous directive of them all! Basically, the `preload` directive is an in-browser-built directive that comes straight from the browser creators. This means that your Web App can be hard-coded into the actual *Browser* to always use HTTPS. Again, whilst this would mean no redirects, and therefore a performance boost, once you're on this list; it's ***very*** difficult to get back off it! Considering that Chrome takes around 3 months from build-to-table, and that's only for the people who auto-update, you've got a *huge* wait-time if you make a mistake. So we have ourselves here an incredibly powerful, yet actively quite dangerous Security feature. The key here is ensuring you **know** your security measures inside-out, and using discretion. Whilst I don't recommend you submit your site to the `preload` directive, if you wish to - you [can here](https://hstspreload.org/). **Note** - it is *not* a requirement to use preload to utilise HSTS. The only Header you need apply is the max-age header. If you are going to use the HSTS protocol, start out with a small `max-age` - something like a few hours, and continue to ramp it up over a period of time. This is also the advice Google Chrome give. If you use the `includeSubDomains` directive, be sure you don't have internal (company.mysite.com) subdomains that would be unreachable if affected. If you're going to submit your Web App to `preload`, follow the official guidelines, and make sure you know exactly what you're doing - (which I'm not entirely confident of myself!) ## Using the X-XSS-Protection Header XSS (Cross Site Scripting) is the most common of all Web App attacks. XSS occurs when a malicious entity injects scripts to be run into your app. A few years back, most web browsers added a security filter for XSS attacks built into the browser itself. Now whilst in theory this was a good step, they did tend to throw-up false-positives quite often. Due to this, the filter can be turned off by the User. (As the option should be available, in my opinion.) To ensure our Users are protected, we can force this filter (worth it), on our DApp by using the `X-XSS-Protection` Header. This Header is widely supported by common browsers, and something I'd recommend using every time. To apply this header to your Node.js app, you should include the following: ```js function requestHandler(req, res) { res.setHeader( 'X-XSS-Protection', '1; mode=block' ); } ``` Note the two *directives* in this header: `1` is simply acts as a boolean 1 or 0 value to reflect on or off. `mode=block` will stop the entire page loading, instead of simply sanitising the page as it would if you excluded this directive. If you're a security-freak like myself, and a user of the Chromium browser, you could even go one-step further than this and set the directives like so: X-XSS-Protection: 1; report= Now, if the browser detects an XSS attack, the page will be sanitized, and report the violation. Note that this uses the functionality of the CSP `report-uri` directive to send a report that I will talk about in the Content Security Policy section below. ## Defend against Clickjacking Clickjacking occurs when a malicious agent injects objects / iFrames into your DApp, made to look identical, that actually sends the User to a malicious site when clicked. Another common, and possibly more scary example is that malicious agents insert something like a payment form into your DApp, that looks identical to your DApp, but steals payment details. Now, whilst this *could* be a very dangerous issue, it's very easy to mitigate, with almost no impact on your DApp. Servers offer Browsers a Header Protocol named `X-Frame-Options`. This protocol allows us to specify domains to accept iFrames from. It also allows us to state which sites our DApp can be embedded on. With this protocol, we get three fairly self-explanatory options/directives: `DENY`, `ALLOW-FROM`, and `SAMEORIGIN`. If we choose `DENY`, we can block all framing. If we use `ALLOW-FROM`, we can supply a list of domains to allow framing within. I use the `SAMEORIGIN` directive, as this means framing can only be done within the current domain. This can be utilised with the following: ```js function requestHandler(req, res) { res.setHeader( 'X-Frame-Options', 'SAMEORIGIN' ); } ``` ## Content Security Policy (CSP) CSP is another major topic when it comes to Server-Browser security for Web Apps. At a high-level; Content Security Policies tell the browser what content is authorised to execute on a Web App, and what will block. Primarily, this can be used to prevent XSS, in which an attacker could place a `