It is not very uncommon to see pages that include a “returnUrl” parameter, usually within authentication flows. At times, the browser will run some script (like a call to an analytics service) and then another script issuing a redirect (through setting location.href etc.)
There are also other cases where UGC can find its way into JavaScript blocks. People might want to have their script do fancy stuff with the page’s data.
var url = '<%=viewData.returnUrl%>';
or
var commenterName = '<%=viewData.newComment.authorName%>';
for e.g.
Now for the “stating the obvious”:
Just like any other UGC, this type of content must be sanitized to prevent XSS attacks.
Not to long ago I was called to do a security inspection on a web application’s codebase. During which, some very few XSS holes were detected using JavaScript injection. This was quite surprising to me, as I knew that all content injected into JavaScript was being sanitized by the team.
Digging further I found out that they did call a sanitize function on UGC, just not the correct function. What they did was to run a JSON formatter over the UGC string, a thing that was solving JS errors occurring from string quoting problems, but it did not eliminate malicious scripts.
The weird thing was that the team was already using the AntiXss library (which is a very aggressive, white list based input sanitation library for .NET), for html fragments. The library also have a JavaScript Encode function. Switching the sanitation function of the team from calling the JSON library to calling the AntiXss library fixed the problem for good.
e.g. code to demonstrate the difference between the methods:
static void Main()
{
var ugc = "';alert('xss');'";
Render(JsonConvert.SerializeObject(ugc));
Render(AntiXss.JavaScriptEncode(ugc));
}
static void Render(string encoded)
{
Console.WriteLine("var returnUrl = '"+encoded+"';");
}
The output from the above snippet is:
var returnUrl = '"';alert('xss');'"';
var returnUrl = ''\x27\x3balert\x28\x27xss\x27\x29\x3b\x27'';
There are a couple of things to learn from that story:
And guess who is the craziest one.
Client side validation is good right? so you have this field of User Generated Content, which is exposed via a textarea element on your page. For e.g. – comment on blog post.
Now you have a limit of N characters on the field, maybe enforced within a DB constraint or whatever.
function validateMaxLength(elmId) {
var element = document.getElementById(elmId);
var elementContent = element.value;
var elementContentLength = elementContent.length;
return elementContentLength <= N;
}
or something like that.
BUT
think again.
Assuming the element’s content was something like
the element contains at least one newline
how would you count newlines? would you count two characters per newline (for \r\n)? or only one?
When I faced that problem I checked how the browser is counting the newlines. I ran a quick test as saw that it counts newlines as a single character. Since the content was needed to be presented within a web element anyway, and newlines were to be changed to <br/> tags at render time anyway, I decided to have the server code make sure that incoming strings will use only \n for newlines, then validate the length, then store in the DB.
Now the client side JS matched the server criteria.
Case closed.
Or was it?
After a little while I got a bug opened by the QA team about inconsistency between client and server validation regarding lengths of string.
Checked it, and was about to close the bug with a “works for me” message, but then it hit me.
On IE, newlines are \r\n, so it reports too many characters, and the validation might fails wrongfully. Since I mostly use Chrome for day-to-day, and since I did not suspect *that* to be a cross-browser issue, I never tested it on IE during development.
Good old string.replace
elementContent = elementContent.replace('\r\n','\n');
Ken,
the cross-browserer
How lame can you get?
It is even misspelled.
The funniest saddest thing is the source of this page:
<script language="JavaScript">
if (document.all) {
document.writeln(...);}
else {
document.writeln("<p><font color=\"#999999\"><b>Error ! The current browser is either too old or too modern (usind DOM document structure).</b></font></p>");}
</script>
So many bad practices in a such a small snippet. And the stuff in the (…) part was too painful to paste.
I do quite a bit of javascript stuff lately, and I wanted to enjoy the easier syntax of array methods such as forEach, find etc.
As the current project is not using prototype.js, but rather a different js stack (jquery, various jquery plugins, EJS, and a bit more) I did not have the extended Array stuff that comes with prototype.js
But before I ran off to add the needed methods to Array’s prototype, I had an annoying voice in the back of my head, whispering “extending Array’s prototype is evil, extending Array’s prototype is evil”, so I looked at alternatives.
I went ahead to implement a MyArray (or Array2) type of solution.
using one method of JS subclassing I thought of
var MyArray = function() { }; MyArray.prototype = new Array; MyArray.prototype.forEach = function(action) { for (var i = 0, l=this.length; i < l, ++i) action(this[i]); }; ...
the problem with that approach is that IE does not like Array subclassing, thus the .length property becomes unreliable, rendering the whole idea of subclassing Array useless.
It would work, however things like
if (anArrayInstance instanceof Array)
will naturally break.
function extendArray(arr) {
if (arr.__wasExtended) return;
arr.forEach = function(action) {
for (var i = 0, l=this.length; i < l, ++i)
action(this[i]);
};
arr.__wasExtended = true;
}
which is wrong as any instance will get a copy of all the functions, so too much memory will be used for non-core functionality
just read http://dean.edwards.name/weblog/2006/11/hooray/
the idea is to use an Array object from a separate iframe, thus enjoy the Array (instanceof), but not interfere with existing Array object on the main window
On top of all that. all three alternatives are problematic, as a regular
var a = [];
will not be extended. which is not such a big problem if you're disciplined enough, but it's terribly annoying to need to extend every array you want. think about JSON data you get from a service. you'd first have to iterate over the object graph and extend all of the arrays. yuck.
Now, do you remember that annoying voice from the back of my head? I decided to stand up to him !
Why actually not extend the Array prototype and be done with it?
It will solve the “instanceof” problem, it will solve the need to apply the functions manually on all arrays (as any [] will natively have the new functions), and it wouldn’t cost much memory as it will only be added to the single prototype of all array instances.
The usual reason for not wanting to do so, is that it would break the associative array ‘feature’ of javascript, and you won’t be able to
for (var i in myArray)
anymore.
You know what? that reason is a total bullshit.
Why? cuz there’s not such thing as an associative array in javascript !
If anything, the Object object is similar enough. However the Array object should be used with 0-based integer index, just like any native java/c#/c/whatever array.
Removing that ‘problem’ from the equation, and we can resort back to stuff like
Array.prototype.numSort = function() {
this.sort(function(a, b) { return a - b; });
return this;
};
Array.prototype.forEach = function(action, index) {
for (var i = 0, l = this.length; i < l; ++i)
action(this[i], index);
};
Array.prototype.find = function(func) {
for (var i = 0, l = this.length; i < l; ++i) {
var item = this[i];
if (func(item))
return item;
}
return null;
};
Array.prototype.where = function(func) {
var found = [];
for (var i = 0, l = this.length; i < l; ++i) {
var item = this[i];
if (func(item))
found.push(item);
}
return found;
};
You just have to *love* dynamic languages :)
I’ve just been asked the following question by a friend:
in javascript - how do i get the text of an html-element, which doesn't include text of all the children? firefox only
Every html DOM element has a collection of direct children, called childNodes. Each node has a type, and text nodes (those are text portions that are part of an element’s inner content) have ‘3’ for their type.
So, the following code is the solution:
function extractFirstLevelTextFrom(elm) {
var text = '';
for (var i =0; i < elm.childNodes.length; ++i) {
if (elm.childNodes[i].nodeType==3)
text += elm.childNodes[i].nodeValue;
}
return text;
}At time you'd want to store data, related to a DOM element.
storing it directly into the element (either by elm.someArbitraryName = value, or with setAttribute) is wacky. Some browsers might not like you using non standard attributes, so you start using things like 'alt' and 'rel'. Then again, these things has meaning, and storing arbitrary data is ... well, uncool to say the least.
jQuery.data() to the rescue. As jQuery objects are wrappers that HasA DOM elements, and not the DOM elements themselves (as in prototype), storing data on them is like storing data on POJSO (Plain Old JavaScript Objects), and the data() functions allows for an easy way of doing that.
Read on that (and of a few other jQuery tips) at http://marcgrabanski.com/article/5-tips-for-better-jquery-code
explanation (before the wife kills me): I have some free time in the coming months, so I'm looking for interesting consulting gigs.
So, if you're in a company / dev team, and looking for some help with Castle (Windsor, MonoRail), NHibernate, or general information system design and architecture advices or training, setting up build and test environments, or any other of the things I rant about in this blog, then I'm your guy.
I also do web-client ninja work, dancing the crazy css/html/javascript tango (jQuery: yes, Ms-Ajax: no)
I currently live in Israel, but I'm fine with going abroad for short terms if you're an off-shore client.
you can contact me at "ken@kenegozi.com"
Serving as a mental note, and as a service to dear readers who hadn't been bitten by this yet.
javascript's parseInt method is not the same as .NET's int.Parse.
there's this 'radix' argument which is meant to tell the parseInt method whether we want to treat the string we parse as binary, octal, decimal, hexadecimal or whatever.
Now the naive programmer (a.k.a. myself) would think that the default is always base 10, so parseInt(x) === parseInt(x, 10) for every x.
Apparently parseInt tries to outsmart us, and it's actually guessing the radix if not set. so if x begins with 0x, it would guess hexadecimal, and if x begins with 0 it would guess it's octal.
so, parseInt('010') === parseInt('010', 8) === 8
ok, I can live with that maybe.
however it would also 'guess' that 09 is octal (even though 9 is not an octal digit !) thus parseInt('09') === 0
I found this by chance, when a Date.parse method I have was parsing "09/07/2008" into a date-info object with day==0, causing it to fall back into today's date
So, the lessons we've learned today:
Actually, it's not much of a challenge, but it is a catchy title.
Or is it?
Anyway, that's the details:
I'd kindly ask all of you ASP.NET Ajax wiz guys (and gals), to supply me with a simple UpdatePanel thing.
What should it do?
I want to have a webpage, based on this template, that on dropdown change, will go to the server with the selected value in the dropdown, and update the data (table) with some crap, based on the sent value.
You can leave the actual data retrieval to a simple method returning an array of string array, or you can go and implement a CodeSmith/DAAB/Whatever based supercool data access code. I would ignore it anyway. I want the Ajax stuff.
Now, to the why.
I am doing that MonoRail presentation at Microsoft's Israel IVCUG (Israel Visual C(#/++) User Group) next week. I might be showing some demos, and I want to be fare when I show a comparison to WebForms stuff, and not come up with a crappy code and say "ha ha", but show something that one of you, my-dear-readers-who-actually-uses-asp-net-ajax-for-living, wrote, and is considered a good example.
Also, I'm lazy. Seriously. Creating a presentation takes a LOT of time and effort, and I do not have much of the first, and rather avoid much of the later.
So, please do send me that code, to my-first-name at that-blog's-hostname.
thanks.
I've posted an article to CodeProject about building my Google Ajax Search Enabled Homepage.
So, go there, read it, comment it, vote for it, tell your friends about it, print it and glue it to your forehead, whatever you think is appropriate.
Unless you didn't like it. In that case, you shouldn't do anything. why bother ? :)
I have loaded a new homepage, and used a little of the Google AJAX Search API to make it interesting. Actually, I'm using it now as my browser's default homepage, instead of google.com
Not only that, but I have documented the process of making it, and have sent it to codeproject, to be published, as my first contribution there, in hope for more to come.
So, please leave your impressions, eiether here or in the codeproject article (I'll post the addresss once it will be up).