Cross Site Scripting (XSS) Attacks in React
By: Lance Watanabe
Tags: React, JavaScript, Coding, Learning To Code, Web Development

eval(): The eval function evaluates strings as JavaScript. Therefore, if the attacker injects JavaScript into eval(), your app would run the attacker’s script.

In the component below, we have two input forms that request the user’s first and last name as strings. Then, we call eval() to concatenate the first name + last name to form the full name (We do not include a space in the concatenation for the purposes of this example). However, if the user inputs alert(‘Hacked!’) into the first input and presses submit, the alert() function will execute. Note, since the user didn’t provide a last name, the “full name” will be in the first input.

import React, { useState } from 'react'; const Eval = () => {

const [data, setData] = useState({

firstName: '',

lastName: '',

}); const handleType = (e) => {

setData({

...data,

[e.target.name]: e.target.value,

});

}; const handleSubmit = () => {

eval(data.firstName + data.lastName);

}; return (

<div>

<input

type='text'

name='firstName'

value={data.firstName}

onChange={(e) => handleType(e)}

/>

<input

type='text'

name='lastName'

value={data.lastName}

onChange={(e) => handleType(e)}

/>

<button onClick={() => handleSubmit()}>Submit</button>{' '}

</div>

);

}; export default Eval;

href: In the component below, we ask the user to provide a link. We set the href dynamically in the <a> tag to the user’s provided link. See bold below. Instead of providing a link, the attacker inputs javascript: alert(‘Hacked!’) so when someone clicks on the link, the alert() will be executed.

import React, { useState } from 'react'; const Href = () => {

const [data, setData] = useState({

text: '',

}); const handleType = (e) => {

setData({

...data,

[e.target.name]: e.target.value,

});

}; return (

<div>

<input

type='text'

name='text'

value={data.text}

onChange={(e) => handleType(e)}

/>

<a href={data.text}>click Here</a>

</div>

);

}; export default Href;

dangerouslySetHTML: The name says it all. Each HTML element in JSX has a dangerouslySetHTML property. You can pass HTML into this property as a string and the HTML will be rendered in the DOM.

In the component below, we pass an <img> element into the dangerouslySetHTML property. The only problem is the <img> element includes onerror = ‘alert(\”Hacked!\”)’ which is malicious JavaScript that will be executed if the image is not loaded.

As you can imagine, if you allow the user to dynamically input HTML into the dangerouslySetHTML property, your app would be susceptible to XSS.

It should be noted that React attempts to prevent XSS because it omits<script> tags that are passed into the dangerouslySetHTML property.

import React from 'react'; const DangerouslySetInnerHTML = () => {

const createMarkup = () => {

return {

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

};

}; return (

<div>

<div dangerouslySetInnerHTML={createMarkup()} />

</div>

);

}; export default DangerouslySetInnerHTML;

How can we prevent these attacks? You can escape (replace) reserved characters (such as< and >) with their respective character entities (< and >). Therefore, when the code is rendered, no JavaScript can be executed. Instead, the character entities will be converted to their respective reserve characters.

Also, you can “sanitize” user inputs using a library called dompurify.

https://github.com/cure53/DOMPurify

XSS Protection in React: When we create new elements using the React API, React will automatically review data to auto-escape scripting code. Below is a snippet of the React’s createElement() method.