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>
Don’t do this:
<form action={data}> ...
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>
Don’t do this:
<a href={url}>About</a>
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) }} />
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)} />
Don’t do this:
this.myRef.current.innerHTML = "<div>Hacked</div>";
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
);
});
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
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')}
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>
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
Top comments (0)