loading...
Cover image for 7 security tips for your React application. πŸ”

7 security tips for your React application. πŸ”

vaibhavkhulbe profile image Vaibhav Khulbe Updated on ・7 min read

It happens that in your organisation the very first React application is built with months of dedication, great developers coding with ridiculous decency which is reflected in their clean code practices, the performance index is superb and yes, its user experience is unmatched! The time has come. You've just finished all the major deployment, DevOps stuff and crazy testing. You're about to deploy this wonderful application which will definitely help grow your business a lot. You deploy, you fail and then you reflect...

None of these performance indexes, UX reviews, testing etc matters unless your application is secure. In today's world, data is the most precious gem you can find on Earth. (no, I'm not joking!) Your entire business may collapse in a drift if your application is insecure or one 12-year-old hacker jailbreaks your code to sell for bad stuff. Hence, it's highly important that every application must be secure first. As you're a React dev, here are some of the common tips you'll find around to safeguard that JSX code.

Lock GIF

Eh, don't be that landlord of your React app...

1️⃣ Secure your HTTP authentication

If your application has some authentication feature where users log in or create an account, you need to make sure it's secure because usually the client-side authentication and authorization is the one which is exposed to multiple security flaws which may damage these protocols within the app.

Most prominently, you would've used one of the following methods to add authentication:

Let's take a look at how you can safeguard with JWT:

βœ” Dos and Don'ts ❌

❌ DON'T store your JWT tokens on localStorage. Someone can easily use the browser's dev tools console and write this to get this token very easily:

console.log(localStorage.getItem('token'))

They can now make use of this token to send them to a different location where they may be collecting them! That's bad for both you and your users.

βœ” DO move your tokens from localStorage to a HTTP cookie.

βœ” Else, DO move your tokens to your React app's state.

❌ DON'T keep the secret keys that go into signing your tokens in the browser. Anyone who visits your website can see the different data, cookies, tokens etc. If you're sending the secret keys you should know that they can be used to sign some new tokens!

βœ” DO keep them on your backend. Always sign and verify these keys on the backend.

βœ” DO use long and unguessable secrets. Just like when you create an account and the password field tells you to make a strong and long password, same goes on with these JWT secrets.

❌ DON'T decode the token on client-side. Especially the access tokens. Generally, these access tokens are meant for the APIs powering the application.

βœ” DO keep an expiresAt key on your localStorage. Here's a simple method on how you can add an expiry time for reference.

βœ” DO keep your token payload small. The bigger the payload > the bigger the size of your token > the larger the request when they hit the endpoint > more bandwidth power from your users > the less performant your app.

βœ” DO make sure you're using HTTPS and NOT HTTP under any circumstance. This will make sure your web app has a valid certificate and it sends the data over this secure SSL connection.

I recently came across this comment by Warren, it's insightful.

2️⃣ Secure against DDoS attacks

Typically this security vulnerability occurs when the app isn't secure enough or it has some loopholes in masking the IPs of services. Due to this, it can't interact with the server causing some services to stop. Here are some ways to stop this:

  1. Rate limiting on APIs: you just limit the number of requests to a given IP from a specific source. There's an entire library if you're using Axios called axios-rate-limit.

  2. Add app-level restrictions to the API.

  3. Make calls on the server and NOT on the client-side.

  4. Add some tests to secure the app layer. Here's a good article on the same:

3️⃣ Secure against Cross-Site Scripting (XSS) attacks

XSS is quite risky as the injected code from the attacker will be executed as a legitimate app code, giving the attacker full control over the application running in the user’s browser. It can look as cute as this:

I'm just an innocent code!<script>alert("Unless I'm not 😈")</script>

And here's the same code with some protection from XSS:

I'm just an innocent code!&lt;script&gt;alert("Unless I'm not 😈")&lt;/script&gt;

As you might know, &lt; and &lt; are interpreted as < and > respectively so the browser will not confuse the data for code this time. Some more ways to shield are:

  1. Using the createElement() API.

  2. Using JSX auto escape feature.

  3. Using dangerouslySetInnerHTML to set HTML directly from React instead of using the error-prone innerHTML. Chekout the following thread:

Is there any "behind the scenes" difference from setting an element's innerHTML vs setting the dangerouslySetInnerHTML property on an element? Assume I'm properly sanitizing things for the sake of simplicity.

Example:

var test = React.createClass({
  render: function(){
    return (
      <div contentEditable='true' dangerouslySetInnerHTML={{ __html: "Hello" }}></div>
    );
  }
});

vs

var
…

4️⃣ Secure against Cross-Site Request Forgery (CSRF) attacks

CSRF attacks take place through unauthorized cookies placed within your app by the attacker or by some unintended cookies. It forces an end user to execute unwanted actions on a web application in which they’re currently authenticated. Get some important points to not allow it to happen:

  1. Use those JWT tokens for session management.

  2. Make sure your application reads only the stored CSRF tokens.

  3. Generate relevant token headers by making an authenticated request to the server.

5️⃣ Secure against broken authentication

You enter your authentication details and boom...the app crashes leading to exploitation of credential data. Make sure you have the following stuff ready to not allow it:

  1. Use multi-factor and 2-step authorisation.

  2. Use cloud-based authentication for secure access. Here's an article on Authentication for React apps using AWS Amplify and Cognito.

6️⃣ Secure against libraries and components

There's always a risk involved whenever you use a third-party library, modules, or APIs in your React app. Sure, they do help us a lot in the rapid development of features but who knows their own set of security flaws might destroy your own app!

  1. Always try to manually update these libraries to their latest secure and stable versions.

  2. Similarly, patch old versions of the components with the newer ones.

  3. Before even adding these libraries in your project, make a brief check on its security vulnerabilities if they're listed and note down the possible solutions.

7️⃣ Adding End-to-End Encryption

When I first learned that WhatsApp chats will be end-to-end encrypted I was so much happy! Heck, they even have a PDF explaining how they do this...

This encryption type makes sure that the data shared is involved within your React application and nowhere else. All third party will be denied access to transfer any confidential data. Read this article here on DEV which goes through the entire process of making a chat app on React with end-to-end encryption:


Where to next? πŸ€”

Have a look at the following resources for more help:

Thanks for reading, I appreciate it! Have a good day. (βœΏβ—•β€Ώβ—•βœΏ)



πŸ“« Subscribe to my weekly developer newsletter πŸ“«

PS: From this year, I've decided to write here on DEV Community. Previously, I wrote on Medium. If anyone wants to take a look at my articles, here's my Medium profile.

Posted on by:

vaibhavkhulbe profile

Vaibhav Khulbe

@vaibhavkhulbe

πŸ‘¨β€πŸ’» Freelance web developer/designer/writer ✍ | πŸ“§ Subscribe to my weekly dev newsletter with 50+ resources: https://mailchi.mp/f59beeac6b9b/devupdates

Discussion

markdown guide
 

In section 2, I'm not sure I'm understanding. Steps 1 & 2 seem to be about changing the behaviour of React as a client. Rate-limiting your app's calls to the server does not prevent a DDOS attack, it's just ensuring many of your legitimate clients have a more even experience when a server takes too long to honour requests. I would only use a client-side rate limiter as a temporary fix for any network traffic issue, you need to look to more fundamental issues with your server code and infrastructure, don't treat your own customers as attackers! And DDoS' by definition don't come from the same IP, and won't bother using your React client to do it. It's also not really a React-specific issue, React is client-side, it's more like an issue for neXt, express, koa or whatever you're running on the server.
I don't understand what 3 means, would you be able to write a little more to clarify?
And 4 seems to be related to the next section on XSS attacks.

 

Hey Jodi!

  1. To some extent, I do agree with you that rate limiting isn't a permanent fix. The rate-limiting is applied so that only a specific number of requests would be accepted by the server. It should reject the attacker's request when it comes. And yes, this is the case when you use Express/Node for the backend. Of course, not all API stuff can be done solely on client-side when you want to secure your app.

  2. I got to know about point #3 from this article by Philippe. It has details of what you're asking.

  3. Point #4 is about CSRF and NOT XSS.

Thanks!

 

Oh, I think I'm starting to understand your point of view, DDoS' from your React app because it's been subverted. It's just a little odd because I don't see points 2-4 from that section being anything to do with DDoS'ing.
Am I correct in thinking that point #3 you mean URLs that the client can call should originate from the server and not be dynamically-generated in the client? This is to avoid things like erroneous values causing ReDoS'.
It also occurred to me that you don't mention CSP, which would be a very good technique for reducing the chance of invasive XSS via external script calls.

I don't know much about ReDoS and same for the CSP that's why I didn't write about these. But thanks for your information, people will definitely learn something cool!

ReDos is where you exploit a regex (and these are often used for validation, which can be worrying when it's cited as a way of preventing attacks!) that causes an exponential processing loop that slows the server down (mitigating that with rate limiting makes sense).
CSP is where you add headers from the server to indicate to the browser what kind and from where resources are allowed to be loaded onto the page. Content from any places not explicitly mentioned are blocked. Helps with things like defacing too.
Thanks for writing about this anyway, more awareness of security issues is always good, and it's not an easy topic to write about.

Ah, I see. Will look into these two in future. Thanks for writing about this :)

And yes, it's quite challenging... πŸ₯΄

 

only a specific number of requests would be accepted by the server. It should reject the attacker's request when it comes

**Sent **to the server, surely? The web application just makes requests over HTTP. Axios can limit for flood protection and better user experience for non-malicious users, but if someone was going to DDOS you they would intercept the API call and just replay that repeatedly, that sort of security should never be done in Javascript!

Unless you are using a JS backend too, I guess.

The only real way to prevent DDOS is a security layer at server level. Anything client side can be overridden. The golden rule of security is you never trust the web client!

 

Even the first suggestion can be dangerous, since cookies are not safe by default. You need to make sure to use SameSite=Strict, and not every browser current supports that flag.

Additionally, there are some problems with even doing that though, because it means you can't actually use the token to do anything valuable by interacting with other domains. For instance, let's say you want to take your access token and use it to access other services which also support OIDC JWT complaint access tokens. Your app needs to have access to them. Which means cookies won't work because they won't send them cross domain. Take Authress for example which handles user permissions. You can take the access token from the UI and send it to Authress, and where the token will be verified for authenticity before granting permissions. While you can store it in cookies, doing so without protections is both unsafe and feature limiting.

 

Hi Warren, thanks for the insight! I just started with security, hence don't know much in detail. I just shared what I learned (till now). I've added your comment in the article so that others can check.

 

Insightful piece! Thanks πŸ˜„