I happen to read about XSS and how to avoid it. From what I have read, I came to know that we need input filtering, proper handling of application code and output encoding to make the web application somewhat XSS safe. After going through several articles, several doubts still persist.
-
When I tried jQuery.text(“untrusted_data”) or element.text=untrusted_data, the
browser seems to be encoding the content perfectly, but I have read somewhere else that client-side encoding should not be trusted and you have to “always” encode at the server-side. Why is client-side encoding considered not safe ? -
Whenever I tried to set value using jQuery.val(untrusted_data) or element.value=untrusted_data it seems to be safe enough. So is it really XSS safe or did I miss any case here ?
- Also, I happen to read somewhere that jQuery.setAttribute(attrName,untrusted_data) and setAttribute(attrName,untrusted_data) are generally considered safe only if the Attribute Names doesn’t include URL Context based attributes(src,href etc) or Event Handlers(onClick,onMouseOver etc). If that is the case, how am I supposed to set an href attribute by using setAttribute(“href”,untrusted_data)? Is encodeForHtmlAttribute(untrusted_data) from server-side the right way of approach ?
- How should I handle dynamic html creation. Consider the below example
<div id="divName1" onClick="copyData()">untrusted_data</div>
<div id="divName2"></div>
function copyData()
{
var divValue = jQuery("#divName1").html();
jQuery("#divName2").html(divValue);/XSS Here
}
What I want to achieve here is to get the text from divName1 and paste it to divName2’s content. The code I wrote above is XSS vulnerable. I can change this to
jQuery(“#divName2”).text(divValue)
So, this will ensure encoding, but as I understood, we say that client-side encoding is unsafe and only server-side encoding should be used. How should I write this to be XSS safe without using client-side encoding? I am a bit confused here :(.
Please help me out to clear these doubts.
This is a lot of questions at once.
Client-side encoding is fine as long as it is done properly and consistently. Client-side encoding often has a lower bar since it does not need to worry about character-encoding level attacks like UTF-7 attacks.
Assuming
untrusted_datais a string and the element whose value is being set is a regular text node in a flow or block element then you’re fine. You might run into trouble if the node whose value is being assigned is a text node in a<script>element or a URL, event handler, or style attribute node or anything related to<object>.That is partially correct. Other attributes have sharp edges like
styleand many things related to<object>and<embed>, and<meta>.If you don’t know much about the attribute then don’t expose it to untrusted data.
Things that are generally safe are attributes that contain textual content like
title, or that have enumerated values likedir=ltranddir=rtl.Once you’re dealing with attributes that take more complex values you’re at risk of attackers exploiting obscure browser extensions like
-moz-bindinginstyleattributes.Landmines seem to be safe until you step on them.
You can’t conclude much from something “seeming safe”. You really do need to look at it and understand what can potentially go wrong, and arrange things so that you are at risk only when there is a perfect storm of things going wrong (P(disaster) = P(failure0) * P(failure1) * …) and that you are not at risk when only one thing goes wrong (P(disaster) = P(failure0) + P(failure1)*P(!failure0) + …).
Don’t do it without whitelisting the protocol.
No. HTML encoding the value passed to
setAttributeis redundant and will not help preserve any security properties.<iframe srcdoc>might be a rare exception since its content is HTML if my recollection of recent spec changes is correct.Don’t muck around with HTML. Browsers’
.innerHTMLgetters are buggy and sometimes that leads to exploits as with backticks acting as value delimiters in IE. Just clone the nodes from one to the other. Something like the below should do it:That’s fine if all you want is the textual content.