Using properties that set plain text values are great if you’re only adding text, but if you’re adding a lot of markup around it, using document.createElement()
for every element can get tedious. Properties that inject HTML like Element.innerHTML
and Element.outerHTML
properties are so much easier.
In this tutorial, we’re going too look at a technique that allows you to use HTML string injection while also reducing your risk of XSS attacks: encoding. Let’s dig in!
To make third-party strings safer to use, you can encode the content before injecting it. Encoding is the process of converting
For our purposes, encoding is the process of converting any characters that aren’t letters or numbers into their unicode equivalents. This will cause them to be rendered as plain text rather than markup.
If your third-party code is not allowed to contain any markup, you can use a helper method to encode your string: encodeHTML()
.
/**
* Encode the HTML in a user-submitted string
* https://portswigger.net/web-security/cross-site-scripting/preventing
* @param {String} str The user-submitted string
* @return {String} str The sanitized string
*/
function encodeHTML (str) {
return str.replace(/javascript:/gi, '').replace(/[^\w-_. ]/gi, function (c) {
return `&#${c.charCodeAt(0)};`;
});
}
This works by finding every character that’s not whitespace (), a dash (-
), or an underscore (_
), and replacing it with an encoded HTML string instead. As a result, those characters are rendered as literal text strings rather than as HTML.
It also uses the String.replace()
method to find and replace all instances of javascript:
. Otherwise, they could be used to run JS when a link is clicked.
let thirdPartyString = `<img src=x onerror="alert('XSS Attack')">`;
let thirdPartyURL = `javascript:alert('Another XSS Attack')`;
// Renders...
// <p><img src=x onerror="alert('XSS Attack')"></p>
// <p><a href="alert('Another XSS Attack')">View My Profile</a></p>
div.innerHTML =
`<p>${encodeHTML(thirdPartyString)}</p>
<p><a href="${encodeHTML(thirdPartyURL)}">View My Profile</a></p>`;
This approach is lightweight, but has two drawbacks:
��
.A savvy reader also pointed out that the String.replace()
approach to removing javascript:
can be thwarted by using a string like this: javajavascript:script:alert(1)
. This hack would require knowing specifically how our sanitizing code works, but it is still a vulnerability.
Thanks for Reding !!!