.innerHTML??
.innerHTML is a JavaScript tag whos property is used for DOM manipulation. More specifically, it "sets or returns the HTML content (the inner HTML) of an element." (1)
const item = document.getElementById("exampleIdName").innerHTML = "Something had changed!";
Ordinarily, this property is used to examine the current HTML source of the page, including any changes that have been made since the page was initially loaded. But, it can also be used for Cross-site Scripting(XSS).
Cross-site Scripting (XSS)
XSS is a type of attack that injects malicious scripts into otherwise trusted websites. "XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of browser side script, to a different end user." (2)
When the attacker uses XSS to send a malicious script to an unsuspecting user, the end user’s browser has no way of knowing that the script should not be trusted, and will execute the script. "Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by the browser and used with that site. Moreover, these scripts can even rewrite the content of the HTML page." (2)
.innerHTML and security
Using .innerHTML is still a fairly common practice used to edit items on a webpage because setting the value of the .innerHTML lets you easily replace the existing contents of an element with new content. (3) But, because of the way that .innerHTML can add text and elements to a webpage it can easily be manipulated to display potentially undesired or harmful elements within other HTML element tags. Unfortunately, the "flaws" that allow XSS attacks to succeed via .innerHTML are quite widespread and occur anywhere a web application uses input from a user.
item.innerHTML = name; // harmless in this case
// ...
name = "<script>alert('I am John in an annoying alert!')</script>";
item.innerHTML = name; // harmless in this case
---
const name = "<img src='x' onerror='alert(1)'>";
el.innerHTML = name; // shows the alert
Preventing XSS via .innerHTML
The OWASP organization gives a few rules that can help guid in preventing XSS (5) but the rules don't allow absolute freedom in putting untrusted data into an HTML document.
The rules should cover the vast majority of common use cases but there is one built-in safeguard into browsers as just injecting a script element won’t expose you to attacks because this section of the DOM has already been parsed and run.
The best way to prevent .innerHTML XSS is with validating user input or encoding it and using innerText instead of .innerHTML when able. Also, "If your project is one that will undergo any form of security review, using innerHTML most likely will result in your code being rejected. For example, if you use innerHTML in a browser extension and submit the extension to addons.mozilla.org, it will not pass the automated review process." (3)
Is it safe to use
"Safe-ness" of the .innerHTML property is debatable and depends on its use. It's a security issue if it inserts user-provided values, but if you use it to insert static data, or something generated without including any inputs from the user, it's not a security concern.
To best ensure security is is always a good practice to encode or "sanitize" any user data on a page.
Resources
- https://www.w3schools.com/jsref/prop_html_innerhtml.asp
- https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
- https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
- https://www.youtube.com/watch?v=1UsllDMhvN4
- https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.md
Top comments (3)
Would textContent be another alternative besides innerHtml?
Oh yeah! it's a much better/safer alternative as textContent cannot accept HTML tags AND text. textContent only works with the text inside of a tag and wont allow tag code to be passed into it along with the text.
Hey there! I shared your article here t.me/theprogrammersclub and check out the group if you haven't already!