Luckily, React does a few things under the hood to safeguard your application against XSS attacks. Let's rewrite the code in the previous section in React as shown: import './App.
The HTTP X-XSS-Protection response header is a feature of Internet Explorer, Chrome and Safari that stops pages from loading when they detect reflected cross-site scripting (XSS) attacks.
Cross site scripting (XSS) is an attack in which an attacker injects malicious executable scripts into the code of a trusted application or website. Attackers often initiate an XSS attack by sending a malicious link to a user and enticing the user to click it.
Cross-site Scripting (XSS) Cross-site Scripting (XSS) is a client-side code injection attack. The attacker aims to execute malicious scripts in a web browser of the victim by including malicious code in a legitimate web page or web application.
ReactJS is quite safe by design since
so a typical attack like this will not work
const username = "<img onerror='alert(\"Hacked!\")' src='invalid-image' />";
class UserProfilePage extends React.Component {
render() {
return (
<h1> Hello {username}!</h1>
);
}
}
ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
but ...
dangerouslySetInnerHTML
When you use dangerouslySetInnerHTML
you need to make sure the content doesn't contain any javascript. React can't do here anything for you.
const aboutUserText = "<img onerror='alert(\"Hacked!\");' src='invalid-image' />";
class AboutUserComponent extends React.Component {
render() {
return (
<div dangerouslySetInnerHTML={{"__html": aboutUserText}} />
);
}
}
ReactDOM.render(<AboutUserComponent />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Example 1: Using javascript:code
Click on "Run code snippet" -> "My Website" to see the result
const userWebsite = "javascript:alert('Hacked!');";
class UserProfilePage extends React.Component {
render() {
return (
<a href={userWebsite}>My Website</a>
)
}
}
ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Example 2: Using base64 encoded data:
Click on "Run code snippet" -> "My Website" to see the result
const userWebsite = "data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGFja2VkISIpOzwvc2NyaXB0Pg==";
class UserProfilePage extends React.Component {
render() {
const url = userWebsite.replace(/^(javascript\:)/, "");
return (
<a href={url}>My Website</a>
)
}
}
ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
const customPropsControledByAttacker = {
dangerouslySetInnerHTML: {
"__html": "<img onerror='alert(\"Hacked!\");' src='invalid-image' />"
}
};
class Divider extends React.Component {
render() {
return (
<div {...customPropsControledByAttacker} />
);
}
}
ReactDOM.render(<Divider />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Here are more resources
Exploiting Script Injection Flaws in ReactJS Apps
The Most Common XSS Vulnerability in React.js Applications
How Much XSS Vulnerability Protection is React Responsible For?
Avoiding XSS in React is Still Hard
Avoiding XSS via Markdown in React
React automatically escapes variables for you... It prevents XSS injection via string HTML with malicious Javascript.. Naturally, inputs are sanitized along with this.
For instance let's say you have this string
var htmlString = '<img src="javascript:alert('XSS!')" />';
if you try to render this string in react
render() {
return (
<div>{htmlString}</div>
);
}
you will literally see on the page the whole string including the <span>
element tag. aka in the browser you will see <img src="javascript:alert('XSS!')" />
if you view the source html you would see
<span>"<img src="javascript:alert('XSS!')" />"</span>
Here is some more detail on what an XSS attack is
React basically makes it so you can't insert markup unless you create the elements yourself in the render function... that being said they do have a function that allows such rendering its called dangerouslySetInnerHTML
... here is some more detail about it
Few things to note, there are ways to get around what React escapes. One more common way is when users define props to your component. Dont extend any data from user input as props!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With