React XSS
Tags: react, security, architecture
Published: 2022-08-23 21:01:00

XSS attacks or Cross-site scripting are a type of attack in which malicious code is injected into a web page and then executed.

This malicious code can steal your cookies, modify the content or take control of an entire webpage.

The content of this article:

- Attacks
- DOM-based XSS attacks
    - eval
    - href
    - dangerouslySetHTML
- Simple protection from XSS attacks
- React XSS protection

## Attacks
Starting about mid-2012, the research community started using two new terms to help organize the types of XSS.
Types of XSS attacks since mid-2012:
![Types of XSS attacks](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/61u6eo6zr785vtvsa2ge.png)

## DOM-based XSS attacks in React

These attacks belong to the subset of Client cross-site scripting as the data source is from the client side only.

![DOM-based XSS attacks in React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rva8xh1wu7ioeylzclsw.png)
I will show you three examples of DOM-based XSS attacks in this article.
We will look at `eval`, `href` and `dangerouslySetHTML` vulnerabilities.

### eval
The `eval()` function evaluates a string and returns its completion value.
The issue of the eval function is that you can paste malicious javascript code inside and execute it.
Let’s make an example, here is a code snippet in JSX code

```
import React, { useState } from 'react';

const Eval = () => {
    const [data, setData] = useState();

    const handleType = (e) => {
        setData(e.target.value);
    };

    const handleSubmit = () => {
        eval(data);
    };

    return (
        <div>
            <p>Place this code inside input: <code>alert('Hacked')</code></p>
            <input
                type='text'
                name='firstName'
                value={data}
                onChange={(e) => handleType(e)}
            />
            <button onClick={() => handleSubmit()} className="button">Submit</button>{' '}
        </div>
    );
};

export default Eval;
```
And below is a result of the code snippet
![eval result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eb157f6nl4i5lcwlcv3y.png)
We use the user's browser and user input to execute a simple alert function and in real life, the attacker can use another javascript malicious code to make something terrible with your webpage, cookies.

### href
`href` is an attribute of an element. The `<a>` element defines a hyperlink, which is used to link from one page to another.
As an example, we can embed user input inside a href and this is an issue. You can see in the code snippet below, we use a data variable to fill href attribute and data fills with an input element.

```
import React, { useState } from 'react';

const Href = () => {
    const [data, setData] = useState();
    const handleType = (e) => {
        setData(e.target.value);
    };

    return (
        <div>
            <p>Place this code inside input: <code>javascript: alert('Hacked');</code></p>
            <input
                type='text'
                name='text'
                value={data}
                onChange={(e) => handleType(e)}
            />
            <a href={data} className="button">Click Here</a>
        </div>
    );
};

export default Href;
```
Execution of code:

![href result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxjzzgj19r4l3jctu41o.png)

### dangerouslySetHTML
This is a property in HTML code that you can use HTML elements in react code instead of `innerHTML` function. The content of `dangerouslySetHTML` is dynamic and skips the comparison against the virtual DOM. As you can understand it is the third XSS vulnerability. Below is a code and result of execution
```
import React from 'react';

const DangerouslySetInnerHTML = () => {

    const placeHtml = () => {

        return {

            __html: "<img onerror='alert(\"Hacked!\");' src='invalid-image' />",

        };

    };

    return (

        <div>

            <p>We inserted img inside div using dangerouslySetInnerHTML property and add js code in onerror attribute</p>

            <div dangerouslySetInnerHTML={placeHtml()} />

        </div>

    );

};

export default DangerouslySetInnerHTML;
```
Result of render:
![dangerouslySetHTML result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2w6qo09m66vikz9isykk.png)

## Simple protection from XSS attacks
You can replace reserved characters (such as `<` and `>`) with their respective character entities (`&lt;` and `&gt;`).
As a result, the code is rendered, no JavaScript code can't be executed, and character entities will be converted to their respective reserve characters.
Also, you can use “sanitize” user inputs using a library called [dompurify](https://github.com/cure53/DOMPurify).

## React XSS protection
As you can see the most vulnerable place is input and we have an article about controlled and uncontrolled components in React documentation.
Below you can read a blockquote from the React official documentation:

> In the form elements are either the typed ones like textarea. input or the selected one like radio buttons or checkboxes, whenever there is any change, made it is updated accordingly through some functions that update the state as well.
We recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component.
In HTML, form elements such as <input>, <textarea>, and <select> typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState().
The alternative is uncontrolled components, where form data is handled by the DOM itself.
To write an uncontrolled component, instead of writing an event handler for every state update, you can use a ref (createRef) to get form values from the DOM.

## Summary

Protecting your React application to prevent cross-site scripting is not a one-step process. The best way to protect React applications from XSS attacks is to prevent them earlier in your codebase. You can create a list of recommendations for your teammates.

Here is my list:
1. Use dangerouslySetHTML and createRef in very specific use cases.
2. Don't mutate DOM directly as we can make it with React.
3. Use React functionality instead of writing personal techniques. READ documentation.
4. Validate all data that you have and income data (from user and from API)
5. Don't create your personal sanitization libraries, select the best among other libraries from trusted developers.