How to Defend Against XSS Attacks: Encoding, Whitelisting, and Node.js Safeguards
The article explains the nature of XSS, illustrates how attackers inject malicious scripts through user input, and provides practical prevention techniques such as HTML escaping, whitelist filtering, and reusable Node.js middleware with code examples and detailed usage.
XSS (Cross‑Site Scripting) occurs when malicious code is not filtered and is mixed with legitimate website code, making the browser unable to distinguish trusted scripts, which leads to execution of the malicious script.
Typical user‑generated content is displayed in fixed containers or attributes as plain text.
Attackers exploit these input fragments, concatenate specially crafted strings, and break the original placement constraints to create executable code snippets.
By injecting scripts into the target site, attackers cause the code to run in users' browsers, creating security risks.
How to prevent XSS attacks
Use HTML escaping to neutralize dangerous characters.
Apply a whitelist approach to allow only safe tags and attributes.
innerText and innerHTML can be used to convert between text and tags.
Encoding (convert tags to special characters)
function htmlEncode(html) {
let output = '';
if (html) {
let temp = document.createElement("div");
temp.innerText = html;
output = temp.innerHTML;
}
return output;
}Decoding (convert special characters back to tags)
function htmlDecode(text) {
let output = '';
if (text) {
let temp = document.createElement("div");
temp.innerHTML = text;
output = temp.innerText; // returns only text nodes, avoiding parsed tags
}
return output;
}Test
let htmlText = "<p><b>looper.zhuo</b></p> ";
let encodeText = htmlEncode(htmlText);
console.log(encodeText); // <p><b>looper.zhuo</b></p>
let text = "<p><b>looper.zhuo</b></p> ";
let decodeText = htmlDecode(text);
console.log(decodeText); // <p><b>looper.zhuo</b></p>Node.js middleware for XSS safety
/**
* Filter special tags and attributes from a string
* @param {String} str Source string
* @return {String} Filtered string
*/
function filterString(str) {
const whiteList = xss.whiteList;
const filter = new xss.FilterXSS({ whiteList });
return filter.process(str);
}
/**
* Escape sensitive characters in a string
* @param {string} originStr Input string
* @return {string}
*/
function escapeHtml(originStr) {
const matchHtmlRegExp = /["'&<>]/;
let str = '' + originStr;
let match = matchHtmlRegExp.exec(str);
if (!match) {
return str;
}
let escape;
let html = '';
let index = 0;
let lastIndex = 0;
for (index = match.index; index < str.length; index++) {
switch (str.charCodeAt(index)) {
case 34: // "
escape = '"';
break;
case 38: // &
escape = '&';
break;
case 39: // '
escape = ''';
break;
case 60: // <
escape = '<';
break;
case 62: // >
escape = '>';
break;
default:
continue;
}
if (lastIndex !== index) {
html += str.substring(lastIndex, index);
}
lastIndex = index + 1;
html += escape;
}
return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
}
/**
* Reverse escaped characters back to original form
* @param {String} html
* @return {String}
*/
function unEscapeHtml(html) {
return String(html)
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
}Usage
let sendData = {};
const content = utilMod.unEscapeHtml(req.body.content); // decode first to allow whitelist filtering
const filterContent = utilMod.filterString(content); // whitelist filter
sendData.content = utilMod.escapeHtml(filterContent); // re‑encodeXSS injection methods:
Embedding malicious <script> tags in HTML text.
Concatenating attacker‑controlled data in inline JavaScript, breaking string or variable boundaries.
Injecting malicious content into tag attributes, using quotes to break out and add new attributes or tags.
Placing executable code such as javascript: in href, src, or similar attributes.
Using event handlers like onload, onerror, onclick to run uncontrolled code.
Embedding background-image:url("javascript:…") in style attributes (modern browsers mitigate this).
Including CSS expressions like expression(...) (modern browsers mitigate this).
HTML escaping is complex; different contexts require different rules, and using the wrong rule can introduce XSS vulnerabilities.
It is recommended to avoid writing custom escaping libraries and instead adopt mature, industry‑standard libraries.
In summary, if developers insert user‑provided text into HTML without proper filtering, they easily create injection vulnerabilities that attackers can exploit to execute malicious code and compromise data security.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Full-Stack Trendsetter
Latest articles, video tutorials, and open-source projects on React, Vue, Angular, Ionic, React Native, Node.js, Mini Programs, and other cutting-edge technologies. A community for sharing and discussing full-stack development trends.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
