DEV Community

Cover image for 13 ways to secure your react.js application
Vishnu Sivan
Vishnu Sivan

Posted on • Updated on

13 ways to secure your react.js application

React is a free open-source front-end javascript library for building user interfaces. It can be used as a boilerplate for single-page web / mobile applications. React is a well-structured framework used to inject javascript codes inside an HTML page for which it uses JSX syntax. This is a very helpful framework for a beginner to develop a dynamic UI effortlessly.

Today, React has become a highly popular framework due to its extra simplicity and flexibility. It is estimated that more than 1,300K developers and over 10.2 million sites utilize React.js.

Nowadays, with more data being shared, the risks associated with the technologies also increase. Even though React has a smaller number of risks than other frameworks, a small carelessness can cause serious complications in your app. React is rich in open-source components. However, the use of unlicensed, rarely used codes and untrusted sources can make your app vulnerable to security slips.

Prevention is better than cure. It is better to take precaution on the common errors or vulnerabilities as your application will be useless without proper security features.

Getting Started

Let’s start with the most common security threats to your react application.

1. Cross-Site Scripting (XSS)

XSS is a serious client-side vulnerability where a hacker is able to add some malicious code to your program which is interpreted as valid and is executed as a part of the application.

2. SQL Injection

SQL injection is a code injection technique used to attack database contents by inserting the malicious SQL queries into the input fields. It allows the attacker to modify(read/write) data or even destroy the entire content.

3. XML External Entity Attack (XXE)

An XXE attack is a type of attack targeted with XML parsers. This occurs when the external entity reference is processed with a weakly configured XML parser which may lead to the disclosure of confidential data.

4. Broken Authentication

Authentication plays a vital role in your application. Even though we have two-factor authentication methods available, the authentication bypass or inadequate/poor authorization as it leads to a security breach in your application. This may expose the entire user information to the attacker who can manipulate the same.

5. Zip Slip

Zip Slip is an archive extraction vulnerability, allowing attackers to write arbitrary files into the system, resulting in remote command execution.

6. Arbitrary Code Execution

Arbitrary code execution is an attacker’s ability to run any code of his choice on the target machine. An arbitrary code execution exploit is a program which is run by the attacker to exploit the target machine using the remote code execution method.

13 React security best practices

1. XSS protection with data binding

Use data binding with curly braces {} and React will automatically escape values to protect against XSS attacks. However, this protection only helps when rendering textContent and non HTML attributes.

Use JSX data-binding syntax {} to place data in your elements.

Do this:

<div>{data}</div>
Enter fullscreen mode Exit fullscreen mode

Don’t do this:

<form action={data}> ...
Enter fullscreen mode Exit fullscreen mode

2. Dangerous URLs

URLs may contain dynamic script content. So, always validate the URL to ensure the links are http: or https: to avoid javascript: URL-based script injection. Use the native URL parsing function to validate the URL and match the parsed protocol property to an allow list.

Do this:

function validateURL(url) {
  const parsed = new URL(url)
  return ['https:', 'http:'].includes(parsed.protocol)
}
<a href={validateURL(url) ? url : ''}>About</a>
Enter fullscreen mode Exit fullscreen mode

Don’t do this:

<a href={url}>About</a>
Enter fullscreen mode Exit fullscreen mode

3. Rendering HTML

We can insert HTML directly into the DOM using dangerouslySetInnerHTML . These contents must be sanitized beforehand. Use a sanitization library such as dompurify on these values before placing them into the dangerouslySetInnerHTML prop.

Try to use dompurify when injecting native HTML codes into the react DOM:

import purify from "dompurify";
<div dangerouslySetInnerHTML={{ __html:purify.sanitize(data) }} />
Enter fullscreen mode Exit fullscreen mode

4. Direct DOM access

If you must inject HTML then use dangerouslySetInnerHTML and sanitize it using dompurify before injecting it into the component. The direct DOM access using refs, findDomNode() and innerHTML also makes our application vulnerable. So, try to avoid the use of these methods and make the use of dangerouslySetInnerHTML for these purposes.

Do this:

import purify from "dompurify";
const App = ({data}: Props) => {
 <div dangerouslySetInnerHTML={data} />
}
<App data={__html:purify.sanitize(data)} />
Enter fullscreen mode Exit fullscreen mode

Don’t do this:

this.myRef.current.innerHTML = "<div>Hacked</div>";
Enter fullscreen mode Exit fullscreen mode

5. Server-side rendering

Use server-side rendering functions such as ReactDOMServer.renderToString() and ReactDOMServer.renderToStaticMarkup() to provide content escaping when sending the data to the client.

It is not safe to combine unsanitized data with the renderToStaticMarkup() output before sending it for hydration. Avoid concatenation of unsanitized data with the renderToStaticMarkup() output.

Don’t do this:

app.get("/", function (req, res) {
  return res.send(
    ReactDOMServer.renderToStaticMarkup(
      React.createElement("h1", null, "Hello World!")
    ) + otherData
  );
});
Enter fullscreen mode Exit fullscreen mode

6. Detecting vulnerabilities in dependencies

Always check the vulnerability index of the dependency before importing it into your project. They might have vulnerable dependencies. So, try to install a stable version of dependencies or the latest version with less vulnerability count.
You can use tools such as Snyk for analyzing the vulnerabilities.

Use the following command in the terminal to run Snyk in your project,

$ npx snyk test
Enter fullscreen mode Exit fullscreen mode

7. Injecting JSON state

JSON and XML are the two widely used formats for transmitting data over the network. However, most of them prefer to use JSON. Also, it is possible to send JSON data along with server-side rendered react pages. So, try to replace < character with a gentle value (Unicode value) to prevent injection attacks.

Always try to replace HTML specific codes from JSON with its Unicode equivalent characters:

window.__PRELOADED_STATE__ =   ${JSON.stringify(preloadedState).replace( /</g, '\\u003c')}
Enter fullscreen mode Exit fullscreen mode

8. Never serialize sensitive data

We often set the initial state of our app with JSON values. This being the case, JSON.stringify() is a function which converts any data into a string even though it is vulnerable. Thus it gives freedom to an attacker to inject a malicious JS object which can modify valid data.

<script>window.__STATE__ = ${JSON.stringify({ data })}</script>
Enter fullscreen mode Exit fullscreen mode

9. Detecting vulnerable versions of React

React had a few high vulnerabilities in its initial release unlike now. So, it is better to keep your react version up to date to avoid the use of vulnerable versions of the react and react-dom . Use npm audit command to verify dependency vulnerabilities.

10. Configuring security linters

We can automatically detect security issues in our code by integrating the Linter configurations and plugins. It gives us the recommendation for security issues and automatically updates to new versions when vulnerabilities exist. Use Snyk ESLint configuration to detect security issues in your code.

Use Snyk to find and fix vulnerabilities in open-source libraries and also to scan your projects for license compliance.

11. Dangerous library code

This library code is often used to perform dangerous operations like directly inserting HTML into the DOM. So, avoid libraries that use innerHTML, dangerouslySetInnerHTML or unvalidated URLs. Also, configure Linters to detect unsafe usage of React’s security mechanisms.

12. Implement a Web Application Firewall (WAF)

The WAF is just like our windows firewall that monitors the network traffic. It is capable of detecting and blocking malicious content by analyzing the network traffic.

We can implement a WAF mainly in three ways in your application:

  • Network based firewall on the hardware level
  • Host based firewall on the software level (by integrating into the app)
  • Cloud based

13. Principle of least privilege for database connection

It is important to assign the right database roles to various users in your application. The lack of user role definition may expose a way for the attacker to perform any CRUD operation on the database without a valid role.

It is also important to never permit admin privileges for your application database to anyone unless it is vital so as to keep the admin privilege allocation minimal. This will safeguard your application and reduce the chance of database attacks.

Thanks for reading this article.

If you enjoyed this article, please click on the heart button ♥ and share to help others find it!

13 ways to secure your react.js application.pdf

Originally posted on Medium -
13 ways to secure your react.js application

Discussion (0)