Vital Tips to Help You Create a Secure React Web Application

The global influx of digital transformation is creating pressure on infrastructure. All the while, threat actors are continually improving their attack techniques. If there is a vulnerability to be found, it will be exploited.

This is why many teams are shifting security to the left, even going as far as evolving their dev methodology from DevOps to DevSecOps.

Developers still have remaining concerns, most of which focus on release time. However, you should not have to compromise fast releases in favor of security. It doesn't have to be a question of either/or.

In this article, you will learn about four methods that you can take advantage of to secure your React apps quickly. These are simple security practices that should not interrupt your workflow.

React Overview

React, commonly misconstrued as a framework, is an open-source front-end JavaScript library for building user interfaces or UI components, maintained by Facebook and a community of individual developers and companies. React can be used as a base in developing single-page applications (SPA) or mobile applications.

React applications are built by using React Components, independent and reusable bits of code. They serve a similar purpose to JavaScript functions, but they work in isolation and return HTML via its render() function.

React is built around two component types, class components and functional components:

  1. Class Component: Requires you to extend from React.Component and create a render function that returns a React element.
  2. Functional Component: Plain JavaScript function, which accepts props as an argument and returns a React element.

4 Ways to Secure Your React App

Review the following best practices to learn how to secure applications running on React. These best practices will help you prevent attacks like cross-site scripting (XSS) and cross-site request forgery (CSRF), which can be a low-profile automated attack but may also be part of an advanced persistent threat, used as the first step in a more extensive attack campaign.

1. Prevent Cross-Site Scripting (XSS)

Cross-Site Scripting (XSS) attacks are a type of code injection, and one of the most common types of XSS attacks is a DOM-based attack. The attacker aims to inject malicious code into a DOM element on your website to perform malicious attacks when users land on the web page, such as stealing user data.

To prevent this, developers need to sanitize untrusted inputs in several places:

  1. HTML (binding inner HTML)
  2. Style (CSS)
  3. Attributes (binding values)
  4. Resources (referring files)

Sanitizing data is best done before displaying the data to the user screen. It cleanses the original data to prevent it from exploiting any security holes in your application.

You will always want to convert untrusted values provided by external users into trusted values, and you can do so by using the DOMPurify library.

DOMPurify sanitizes HTML and prevents XSS attacks by consuming a string full of dirty HTML. It will then remove anything that is considered dangerous HTML, preventing XSS attacks.

import DOMPurify from "dompurify";
const dirtyCode = `I'm some code <img src="..." onload="alert('Here to inject some code');" />`;

const App = () => (
    <div dangerouslySetInnerHTML=\{{__html: DOMPurify.sanitize(dirtyCode)}} />
);

DOMPurify will take the value we've passed along and remove any script HTML elements and contents, preventing code injection and XSS attacks.

2. Avoid Customizing React Libraries

As tempting as it may be to customize React libraries to fit your needs, doing so will make you reliant on the current version of React that you're using. You will find it challenging to upgrade to later versions of React and may miss out on critical security fixes and features.

The best way to make improvements and fixes to React libraries is to share your changes with the community via a pull request. This will allow other developers to review your changes and consider adding them to the next React version.

3. Avoid Risky React API Endpoints

A key advantage of React is that it saves developers from manually editing the browser's DOM to render components, but that does not mean that there won't be times where developers need direct access to the DOM's elements.

In these cases, React provides us with escape hatches, such as findDOMNode and createRef.

Since escape hatches return the native DOM elements and their API, the application can manipulate the element directly without going through React, leaving your application open to XSS vulnerabilities.

To prevent malicious agents from taking advantage of this, there are a few steps that you can take to secure your application:

  • Avoid outputting the HTML code, instead of outputting text
  • Sanitize your data by using DOMPurifier
  • Use proper APIs to generate HTML nodes safely

4. HTTP-Level Vulnerabilities

Cross-Site Request Forgery (CSRF):

CSRF is an attack where a user trusted by an application sends unauthorized, malicious commands. An example of this will be if a user wants to delete their account on your website. To delete their account, they would need to be signed in to your website.

To validate the authentication of the delete request, the session is stored in the browser via a cookie. However, this leaves a CSRF vulnerability on your site. They need to send a delete request to the server with the cookie present in the browser.

A common way to mitigate it is to have the application server send a random authentication token included in a cookie.

The client reads the cookie and adds a custom request header with the same token in all subsequent requests. This makes it possible to reject a request made by an attacker who does not possess the authentication token.

Cross-Site Script Inclusion (XSSI):

XSSI is an attack that allows an attacker's website to read data from your application's JSON API. It exploits a vulnerability on old browsers that enables overriding native JavaScript object constructors.

It can then provide an API URL using a script tag, meaning that you are including someone else's code in your program. You don't have any control over what is in that code, and you don't have any control over the server's security on which it is hosted.

The server can mitigate this attack by making all JSON responses non-executable. For example, this can be done by prefixing them with the string ")]}',\n" and then using code to remove it before parsing the data. An attacker is unable to do so since script inclusion is always the entire script.

React Security

Security is a crucial concern that should be addressed not only by security professionals by also by developers. The simple practice of writing secure code can help prevent the exploitation of bugs and errors.

While there's no such thing as "perfect", and there will always be fixes to make, patches to release, etc., you can adopt a secure code mindset and avoid unnecessary risks.

23