Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some clarifications regarding XSS [closed]

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.

like image 343
Ebbu Abraham Avatar asked Nov 20 '12 07:11

Ebbu Abraham


1 Answers

This is a lot of questions at once.

Why is client-side encoding considered not safe ?

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.

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 ?

Assuming untrusted_data is 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>.

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,

That is partially correct. Other attributes have sharp edges like style and 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 like dir=ltr and dir=rtl.

Once you're dealing with attributes that take more complex values you're at risk of attackers exploiting obscure browser extensions like -moz-binding in style attributes.

it seems to be safe enough

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) + ...).

how am I supposed to set an href attribute by using setAttribute("href",untrusted_data)?

Don't do it without whitelisting the protocol.

if (!/^https?:\/\//i.test(untrusted_data) && !/^mailto:/i.test(untrusted_data)) {
  throw new Error('unsafe');
}

Is encodeForHtmlAttribute(untrusted_data) from server-side the right way of approach ?

No. HTML encoding the value passed to setAttribute is 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.

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.

Don't muck around with HTML. Browsers' .innerHTML getters 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:

var div1 = $('#divName1');
for (var child = div1[0].firstChild(); child; child = child.nextSibling) {
  $('#divName2').append([child.cloneNode(true)]);
}

I can change this to

jQuery("#divName2").text(divValue)

That's fine if all you want is the textual content.

like image 81
Mike Samuel Avatar answered Nov 07 '22 04:11

Mike Samuel