These are many questions at once.
Why is client-side encoding considered unsafe?
Client-side encoding is great if it is executed correctly and consistently. Client-side coding is often of lower value, since you do not have to worry about character-level coding attacks, such as UTF-7 attacks.
Whenever I tried to set a value using jQuery.val (untrusted_data) or element.value = untrusted_data, it seems quite safe. So is this XSS safe or have I missed any case here?
Assuming untrusted_data is a string, and the element whose value is set is the regular text node in the stream or block element, then you're fine. You may run into difficulties if the node whose value is assigned is the node text in the <script> element or URL, an event handler, or a node style attribute or something related to <object> .
Also, I read somewhere that jQuery.setAttribute (attrName, untrusted_data) and setAttribute (attrName, untrusted_data) are usually considered safe only if attribute names do not include attributes based on URL context (src, href, etc.) or Event Handlers (onClick, onMouseOver, etc.). If so,
This is partially correct. Other attributes have sharp edges, such as style and many things related to <object> and <embed> , and <meta> .
If you know little about an attribute, do not expose it to untrusted data. Things that are generally safe are attributes that contain text content, such as title , or that have listed values, such as dir=ltr and dir=rtl .
Once you deal with attributes that take on more complex meanings, you risk that attackers use obscure browser extensions such as -moz-binding in style attributes.
it seems safe enough
Land mines seem safe until you step on them.
You cannot make anything out of something "seems safe." You really need to look at this and understand what can go wrong and arrange for you to be at risk only when a perfect storm of things happened (P (catastrophe) = P (failure0) * P (failure1)) * .. .) and that you are not at risk when only one error occurs (P (disaster) = P (fail0) + P (fail1) * P (! failure0) + ...).
how should I set the href attribute using setAttribute ("href", untrusted_data)?
Do not do this without a white protocol.
if (!/^https?:\/\//i.test(untrusted_data) && !/^mailto:/i.test(untrusted_data)) { throw new Error('unsafe'); }
Is server side encodeForHtmlAttribute (untrusted_data) the correct way?
Not. HTML encoding the value passed to setAttribute is redundant and does not preserve any security properties. <iframe srcdoc> may be a rare exception, because its contents are HTML, if my recollection of recent changes to the specification is correct.
I want to get the text from divName1 here and paste it into divName2. The code I wrote above is vulnerable to XSS.
Do not guess with HTML. Browsers .innerHTML getters are erroneous, and sometimes this leads to exploits, like backticks acting as value separators in IE. Just clone nodes from one to another. This should do the following:
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)
This is great if all you need is text content.