Security in the JavaScript
Written by liyanting on date 21 August 2010 in Javascript .
First, a good measure is to “Pack” the javascript so it isn’t so easily readable, as well as downloads faster. There are a lot of tools available to do this, including this one by Dean Edwards.
Client Side Sanitization
Secondly, because we are inputting data and turn it around to display immediately on the screen, it’s best to do some of that input scrubbing directly in the JavaScript. When a user enters a new list item, we’ll take two steps to scrub it. First we’ll ensure they aren’t naughtily trying to insert immediately executable JavaScript into links:
// Check for JS in the href attribute
function cleanHREF(str) {
return str.replace(/\<a(.*?)href=['"](javascript:)(.+?)<\/a>/gi, "Naughty!");
}
Then we’ll also scrub that input text for any other HTML. Some HTML we will allow, in case users want to format their lists a bit like with <strong> tags and the like. With the function below, we’ll strip away all tags except those set up in a whitelist.
NOTE: The strip_tags() function used below is part of the php.js project, which has ported a number of useful PHP functions to JavaScript.
var $whitelist = '<b><i><strong><em><a>',
// Strip HTML tags with a whitelist
function strip_tags(str, allowed_tags) {
var key = '', allowed = false;
var matches = [];
var allowed_array = [];
var allowed_tag = '';
var i = 0;
var k = '';
var html = '';
var replacer = function(search, replace, str) {
return str.split(search).join(replace);
};
// Build allowes tags associative array
if (allowed_tags) {
allowed_array = allowed_tags.match(/([a-zA-Z]+)/gi);
}
str += '';
// Match tags
matches = str.match(/(<\/?[\S][^>]*>)/gi);
// Go through all HTML tags
for (key in matches) {
if (isNaN(key)) {
// IE7 Hack
continue;
}
// Save HTML tag
html = matches[key].toString();
// Is tag not in allowed list? Remove from str!
allowed = false;
// Go through all allowed tags
for (k in allowed_array) {
// Init
allowed_tag = allowed_array[k];
i = -1;
if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+'>');}
if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+' ');}
if (i != 0) { i = html.toLowerCase().indexOf('</'+allowed_tag) ;}
// Determine
if (i == 0) {
allowed = true;
break;
}
}
if (!allowed) {
str = replacer(html, "", str); // Custom replace. No regexing
}
}
return str;
}
These functions are implemented in js/lists.js before sending off the AJAX request that adds a new list item…
. . .
// AJAX style adding of list items
$('#add-new').submit(function(){
// HTML tag whitelist. All other tags are stripped.
var $whitelist = '<b><i><strong><em><a>',
forList = $("#current-list").val();
newListItemText = strip_tags(cleanHREF($("#new-list-item-text").val()), $whitelist),
. . .
POST vs GET
One last small measure we’ve taken to secure our app is to use POST over GET for all of our AJAX calls. This is done because the GET method should only be used for retrieval, and not for any action that will modify data in any way.
The primary reason not to use GET for modifying data is that a request made using GET is sent in the URL (i.e. http://example.com?get=request&is=this&part=here). There’s an inherent danger in modifying data based on the information passed in the URL in that a user can cause duplicate processing by accidentally refreshing his or her browser.
A secondary, less important reason to use POST is that it’s a little harder to send a bogus request using POST, which provides a (minor) deterrent to malicious users.
2.0 Features
Of course our work as designers and developers is never done. This is a great start on a simple and usable list application, but right away new features jump to mind. Here are some ideas of ways to expand functionality. Perhaps they slightly complicate things, but are all probably great ideas assuming they are implemented well.
- List sharing
Enter an email address for someone to share the list with. Sharing meaning literally collaborative editing. The user would need an account, so if they already have one they would just be emailed and asked to join the list (they can accept or not accept). If that email address did not have an account, they would be promoted to join first. - Multiple lists
Right now a user can have only one list. It would probably be useful for users to keep multiple lists. Perhaps a dropdown menu for toggling between lists and a simple button for adding new ones. Plenty of interface to think about here, including figuring out how to delete lists. - RSS
Each list could have it’s own RSS feed. Options would probably be necessary, like what the RSS feed would contain (e.g. Do you wish to see entries for when list items are completed or not?). Feed URLs could be long gibberish URL’s, so they are essentially completely private unless specifically shared. - iPhone interface
Logging in via iPhone or other mobile device would have a better more optimized experience.
End It with a Giveaway!
In an effort to promote his new book, PHP for Absolute Beginners, Jason is giving away five copies of it at random. To enter the contest, leave a comment on this article and use the text “PHP for Absolute Beginners” in the comment. Make sure you use your real email address so we can get in touch with you. We’ll pick the random winners next Friday.

Even if you don’t win a free copy (or don’t want to wait) we want to give you a little somethin’ somethin’ for sticking through this series: you can get 10% off the eBook version of PHP for Absolute Beginners using this discount code: PHPXBRZQXSIKG (good through 12/31/2009).
What Do You Think?
Give it to us straight: what do you think? What features would you like to see included in the 2.0 version of Colored Lists? Did we miss anything? Are there holes in our code? We’d love to see your optimizations, ideas, and other constructive criticisms; let’s hear it in the comments!





Comments