How to prevent JavaScript injection (XSS) when JSTL escapeXml is false - javascript

I have a form that people can add their stuff. However, in that form, if they enter JavaScript instead of only text, they can easily inject whatever they want to do. In order to prevent it, I can set escapeXml to true, but then normal HTML would be escaped as well.
<td><c:out value="${item.textValue}" escapeXml="true" /></td>
Is there any other way to prevent JavaScript injection rather than setting this to true?

I'd recommend using Jsoup for this. Here's an extract of relevance from its site.
Sanitize untrusted HTML
Problem
You want to allow untrusted users to supply HTML for output on your website (e.g. as comment submission). You need to clean this HTML to avoid cross-site scripting (XSS) attacks.
Solution
Use the jsoup HTML Cleaner with a configuration specified by a Whitelist.
String unsafe =
"<p><a href='http://example.com/' onclick='stealCookies()'>Link</a></p>";
String safe = Jsoup.clean(unsafe, Whitelist.basic());
// now: <p>Link</p>
So, all you basically need to do is the the following during processing the submitted text:
String text = request.getParameter("text");
String safe = Jsoup.clean(text, Whitelist.basic());
// Persist 'safe' in DB instead.
Jsoup offers more advantages than that as well. See also Pros and Cons of HTML parsers in Java.

You need to parse the HTML text on the server as XML, then throw out any tags and attributes that aren't in a strict whitelist.
(And check the URLs in href and src attributes)

This is exactly the intent of the OWASP AntiSamy project.
The OWASP AntiSamy project is a few things. Technically, it is an API for ensuring user-supplied HTML/CSS is in compliance within an application's rules. Another way of saying that could be: It's an API that helps you make sure that clients don't supply malicious cargo code in the HTML they supply for their profile, comments, etc., that get persisted on the server. The term "malicious code" in regards to web applications usually mean "JavaScript." Cascading Stylesheets are only considered malicious when they invoke the JavaScript engine. However, there are many situations where "normal" HTML and CSS can be used in a malicious manner. So we take care of that too.
Another alternative is the OWASP HTMLSanitizer project. It is faster, has less dependencies and actively supported by the project lead as of now. I don’t think it has gone through any GA/Stable release yet so you should consider that when evaluating this library.

Related

XSS: How can I remove JS snippets from a String in C#?

My usecase is actually quite simple.
Let's say I get an input argument like abcdalert(document.cookie); and I want to scrub it off the (document.cookie); part.
What is the most efficient way to do this in ASP.NET C#?
PS: The snippet can be any JS code. Not necessarily alerts.
I recommend the HtmlSanitizer .Net library to apply server side sanitization
https://github.com/mganss/HtmlSanitizer
This library used for cleaning HTML fragments and documents from potential XSS attacks. It uses AngleSharp to parse, manipulate, and render HTML and CSS. It is based on a robust HTML parser that can protect your code from deliberate or accidental "tag poisoning" where invalid HTML in one fragment can corrupt the whole document (which can lead to a broken layout or style)

JavaScript / Lit-element safe way to parse HTML

I am getting some html from my server that I want to put into my page. However I want it to be sanitized (just in case).
However I am not quite sure how to do this.
So far I've tried:
<div .innerHTML="${body}"></div>
Since that should parse it as HTML but I am not 100% sure that this is the best way.
I have also looked at online sanitizers but haven't been able to find any that match my project (Lit-element web component).
Is there a better way to parse HTML and if so how?
Take a look at the DOMParser interface API
document.getElementById('my-target').append(new DOMParser().parseFromString(data, 'text/html').body.children);
It's not clear whether you want to render the html as html or as text.
I seem to remember that lit-html does some things behind the scenes to produce secure templates but surprisingly I cannot find official content to back up that statement. Others have asked about this before.
In that GitHub issue we can see that Mike Samuel mentions that what you're doing is not secure.You can trust Mike Samuel: he's worked in the security field at Google and I had the privilege to listen to one of his talks on the topic two years ago.
Here's a quick example:
<p .innerHTML=${'<button onclick="alert(42)">click</button>'}></p>
This renders a button which produces an alert when you click on it. In this example the JavaScript code is harmless but it's not hard to imagine something way more dangerous.
However this simply renders the code as string. The content is somehow escaped and therefore totally harmless.
<p>${'<button onclick="alert(42)">click</button>'}></p>
In fact similar to React's dangerouslySetInnerHTML attribute you need to "opt out" from secure templating via lit-html unsafeHTML directive:
Renders the argument as HTML, rather than text.
Note, this is unsafe to use with any user-provided input that hasn't been
sanitized or escaped, as it may lead to cross-site-scripting vulnerabilities.
<p>${unsafeHTML('<button onclick="alert(42)">click</button>')}></p>
About DOMParser#parseFromString
In this introductory article about trusted-types we can see that this method is a known XSS sink.
Sure it won't execute <script> blocks but it won't sanitise the string for you. You are still at risk of XSS here:
<p .innerHTML="${(new DOMParser()).parseFromString('<button onclick="alert(42)">click</button>','text/html').body.innerHTML}"></p>

Does Vue, by default, provide security for or protects against XSS?

I am trying to figure out how to protect,
Angular
Vue
React
against XSS attacks. When I visit the Angular official docs,
https://angular.io/guide/security
, it says:
To systematically block XSS bugs, Angular treats all values as
untrusted by default. When a value is inserted into the DOM from a
template, via property, attribute, style, class binding, or
interpolation, Angular sanitizes and escapes untrusted values.
and also:
Angular sanitizes untrusted values for HTML, styles, and URLs;
sanitizing resource URLs isn't possible because they contain arbitrary
code. In development mode, Angular prints a console warning when it
has to change a value during sanitization.
and:
Angular recognizes the value as unsafe and automatically sanitizes it,
which removes the tag but keeps safe content such as the
element.
When I go to the React official docs,
https://reactjs.org/docs/introducing-jsx.html#jsx-prevents-injection-attacks
,it says the following:
It is safe to embed user input in JSX:
and:
By default, React DOM escapes any values embedded in JSX before
rendering them. Thus it ensures that you can never inject anything
that’s not explicitly written in your application. Everything is
converted to a string before being rendered. This helps prevent XSS
(cross-site-scripting) attacks.
But for Vue, I cannot find anything in their docs about XSS protection, or anything that they could provide by default.
My question: Does Vue, by default, deliver any way of protection against XSS attacks, or would I need to look for a 3rd party solution?
When I Google for this subject I get a lot of blog posts sites and articles refering to, for example, this project to sanitize my HTML:
https://github.com/punkave/sanitize-html
There is no built-in sanitizer in vue. As per Evan You's (Creator of Vue) comment on an issue
built-in sanitizer would add extra bundle weight for a rare use case
(when most use cases of v-html are for trusted content); it is also
trivial to add sanitize-html by setting Vue.prototype.$sanitize =
sanitizeHTML and then do v-html="$sanitize(html)".
Check this post : https://github.com/vuejs/vue/issues/6333
One way to help protect against XSS, is to add a Content Security Policy in your html head. It works by restricting the resources (scripts, images) that a page can load and as well as restricting framing of your pages.
For example, the following directive only allow scripts to be loaded from the same origin as the page itself and "apis.google.com".
<meta http-equiv="Content-Security-Policy" content="script-src 'self' https://apis.google.com">
There are other CSP settings that can be used to help mitigate against XSS attacks such as nonces and hashes. For more information visit: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
More additional info than an answer: like mentioned in another post does sanitize-html have a drawback of a 327 KB weight. But there are smaller packages available:
DOMPurify (15 KB)
js-xss (28 KB)
To prevent XSS in our projects we are using vue-dompuritfy-html which has the bonus to cover the recommended eslint rule vue/no-v-html. After installing you can simply use
<div v-dompurify-html="htmlContent" />
I think the accepted answer is misleading. There's a difference between sanitizing HTML and escaping HTML (also called HTML encoding). The former means turning
<img src=x onerror=alert(1)>
to
<img src="x">
while the latter means turning it to
<img src=x onerror=alert(1)>
There's only a handful of cases when you need HTML sanitization. One scenario is when the user needs to write messages with rich text formatting, so you allow the user to write HTML with a few whitelisted tags like i, b and img.
But in 99% of cases, you just want text to be text. So when you write
<h1>{{ userProvidedString }}</h1>
and the user enters
<img src=x onerror=alert(1)>
you want the page to display literally <img src=x onerror=alert(1)>. Most modern frameworks, like Vue, Angular and React do this by automatically HTML encoding output . So yes, Vue does protect against XSS by default.
If you want the browser to interpret the input as HTML, so that the page displays an image and an alert box instead, you can use v-html in Vue, which is equivalent to ng-bind-html in Angular and dangerouslySetInnerHTML in React. In this case you should consider an HTML sanitizer.

Selector interpreted as HTML on my website. Can an attacker easily exploit this?

I have a website that is only accessible via https.
It does not load any content from other sources. So all content is on the local webserver.
Using the Retire.js Chrome plugin I get a warning that the jquery 1.8.3 I included is vulnerable to 'Selector interpreted as HTML'
(jQuery bug 11290)
I am trying to motivate for a quick upgrade, but I need something more concrete information to motivate the upgrade to the powers that be.
My question are :
Given the above, should I be worried ?
Can this result in a XSS type attack ?
What the bug is telling you is that jQuery may mis-identify a selector containing a < as being an HTML fragment instead, and try to parse and create the relevant elements.
So the vulnerability, such as it is, is that a cleverly-crafted selector, if then passed into jQuery, could define a script tag that then executes arbitrary script code in the context of the page, potentially taking private information from the page and sending it to someone with malicious (or merely prurient) intent.
This is largely only useful if User A can write a selector that will later be given to jQuery in User B's session, letting User A steal information from User B's page. (It really doesn't matter if a user can "tricky" jQuery this way on their own page; they can do far worse things from the console, or with "save as".)
So: If nothing in your code lets users provide selectors that will be saved and then retrieved by other users and passed to jQuery, I wouldn't be all that worried. If it does (with or without the fix to the bug), I'd examine those selector strings really carefully. I say "with or without the bug" because if you didn't filter what the users typed at all, they could still just provide an HTML fragment where the first non-whitespace character is <, which would still cause jQuery to parse it as an HTML fragment.
As the author of Retire.js let me shed some light on this. There are two weaknesses in older versions of jQuery, but those are not vulnerabilities by themselves. It depends on how jQuery is used. Two examples abusing the bugs are shown here: research.insecurelabs.org/jquery/test/
The two examples are:
$("#<img src=x onerror=...>")
and
$("element[attribute='<img src=x onerror=...>'")
Typically this becomes a problem if you do something like:
$(location.hash)
This was a fairly common pattern for many web sites, when single page web sites started to occur.
So this becomes a problem if and only if you put untrusted user data inside the jQuery selector function.
And yes the end result is XSS, if the site is in fact vulnerable. https will not protect you against these kinds of flaws.

Angular $sce vs HTML in external locale files

A question regarding ng-bind-html whilst upgrading an Angular app from 1.0.8 to 1.2.8:
I have locale strings stored in files named en_GB.json, fr_FR.json, etc. So far, I have allowed the use of HTML within the locale strings to allow the team writing the localized content to apply basic styling or adding inline anchor tags. This would result in the following example JSON:
{
"changesLater": "<strong>Don't forget</strong> that you can always make changes later."
"errorEmailExists": "That email address already exists, please sign in to continue."
}
When using these strings with ng-bind-html="myStr", I understand that I now need to use $sce.trustAsHtml(myStr). I could even write a filter as suggested in this StackOverflow answer which would result in using ng-bind-html="myStr | unsafe".
Questions:
By doing something like this, is my app now insecure? And if so, how might an attacker exploit this?
I can understand potential exploits if the source of the displayed HTML string was a user (ie. blog post-style comments that will be displayed to other users), but would my app really be at risk if I'm only displaying HTML from a JSON file hosted on the same domain?
Is there any other way I should be looking to achieve the marking-up of externally loaded content strings in an angular app?
You are not making your app any less secure. You were already inserting HTML in your page with the old method of ng-bind-html-unsafe. You are still doing the same thing, except now you have to explicitly trust the source of the HTML rather than just specifying that part of your template can output raw HTML. Requiring the use of $sce makes it harder to accidentally accept raw HTML from an untrusted source - in the old method where you only declared the trust in the template, bad input might make its way into your model in ways you didn't think of.
If the content comes from your domain, or a domain you control, then you're safe - at least as safe as you can be. If someone is somehow able to highjack the payload of a response from your own domain, then your security is already all manner of screwed. Note, however, you should definitely not ever call $sce.trustAsHtml on content that comes from a domain that isn't yours.
Apart from maintainability concerns, I don't see anything wrong with the way you're doing it. Having a ton of HTML live in a JSON file is maybe not ideal, but as long as the markup is reasonably semantic and not too dense, I think it's fine. If the markup becomes significantly more complex, I'd consider splitting it into separate angular template files or directives as needed, rather than trying to manage a bunch of markup wrapped in JSON strings.

Categories

Resources