Book chapter: Browser security principles, same-origin policy exceptions

This is an excerpt from the book Web Application Security: A Beginner’s Guide that describes the intricacies of using script code within the framework of a same-origin policy.

The following is an excerpt from the book Web Application Security: A Beginner’s Guide by Bryan Sullivan and Vincent Liu. This section describes the intricacies of using script code within the framework of a same-origin policy and details key exceptions to the effectiveness of this procedure.

Exceptions to the Same-Origin Policy

However, even here in the real world, there are ways for applications to make exceptions to the same-origin policy. The demand from web application developers for the ability to create full-featured mashups like Amy’s Flowers—but significantly more secure—is just too great to ignore, so browser manufacturers and browser plugin manufacturers have given them the ability to bypass the same-origin policy in certain controlled ways. But if you accidentally misuse these bypasses, you can leave your application open to attack and leave your users at risk of losing their private data. Let’s look at a few ways to get around the same-origin policy, and a few ways to ensure this is done as securely as possible.

HTML ‹script› Element

The HTML <script> element is undoubtedly the most widely used method of cross-origin communication. If you open just about any page on the Internet, chances are good that you’ll find a <script> tag in its page code somewhere. What <script> does is to define a block of client-side script code, usually written in JavaScript. For example, the following <script> block will pop up an alert box in the user’s browser window with the message “Hello JavaScript World!”:

<script> alert('Hello JavaScript World!');</script>

Instead of defining a block of script code directly within the <script> tags, you can also use the script element’s “src” attribute to load script code from some other location on the Internet:

<script src="http://www.site.cxx/some_script.js"/>

This is where the cross-origin communication comes in, because the same-origin policy is not enforced for <script src> tags. Any page is free to load and run script code from anywhere on the Internet.

You should be extremely cautious when using <script src> in your applications unless you have complete control over the script that the tag is loading. If you’re the owner of www.siteA.cxx, and you’re using <script src> to load from some location on siteA.cxx, you’re probably okay:

<script src="http://siteA.cxx/script.js" />

But be careful when pointing <script src> at other domains you don’t own:

<script src="http://siteB.cxx/script.js" />

Whenever a user visits your page that contains this tag, their browser will automatically download the script code from siteB.cxx and run it. If the script code turns out to be malware, it will look to the user as if it was your page that was responsible. And even if siteB.cxx is a completely honest site that would never knowingly host malware, if they get hacked, then so will you and so will your users.

JSON and JSONP

There is one big catch to using <script src>: While you

can point a <script> tag at any site on the Internet without regard to the same-origin policy, it only works if the resource you specify in the “src” attribute is well-formed, valid script. If you try to point it at any arbitrary HTML page, your page code will throw an error and you won’t be able to view the cross-domain data you tried to retrieve. It must be script, valid script, and only valid script.

In the early 2000s, Douglas Crockford, currently a software architect at Yahoo!, realized that it would be possible to create a data format that would also be valid JavaScript code. He called this format JSON, short for JavaScript Object Notation. If you wanted to create a JSON object to represent a music album, it might look something like this:

"artist" : "The Black Keys", "album" : "Brothers", "year" : 2010, "tracks" : [ "Everlasting Light", "Next Girl", "Tighten Up"]}

Many web services now use JSON as their data format instead of XML because JSON is generally more compact, more human-readable, and because JSON objects are also valid JavaScript objects and are easy to work with from JavaScript code. However, web services send data as strings, not native JavaScript objects. If you get a string of JSON from a web service, maybe as the result of an Ajax call (if you’re unfamiliar with Ajax, we’ll cover it later in this section), you’ll need to convert it into an object before you can work with it. There are several ways to do this, but only one of them is really safe.

One popular but insecure way is to use the JavaScript function “eval” to evaluate the JSON string (that is, execute it as if it were code) and create an object from it:

jsonString = '{"artist":"The Black Keys","album":"Brothers"}';var album = eval('(' + jsonString + ')');

This is highly dangerous unless you have complete control over the JSON string being eval’d. If an attacker has any way to add or change items in the JSON, he could potentially add malware to it, which the user’s browser would then execute when it evals the JSON.

Listen to this tip as an MP3

Listen to Book chapter: Browser security principles, same-origin policy exceptions

A better alternative to “eval” is to use the native JavaScript function JSON.parse, which is much more secure and won’t execute malicious script. JSON.parse is available in IE as of IE8, Firefox as of version 3.5, Safari as of 4.0, and all versions of Chrome. If you need to support browsers older than this, it’s still better to avoid “eval” and instead use one of the free JavaScript libraries like jQuery or Prototype that can safely parse JSON.

At this point, you might be wondering why you have to go to the trouble of parsing JSON, and why you can’t just use <script src> to fetch JSON data directly. After all, JSON is valid script code, so <script src> should be able to work with it just fine. Actually, you can do this, but there are some reasons you might not want to. In the first place, using <script src> is essentially the same thing as calling “eval,” so unless you can completely trust the source you’re pulling data from, you could be putting yourself at risk. Second, unless the site serving the JSON supports a callback mechanism called JSONP, you won’t be able to do anything with the returned data. And third, even if they do, it’s still somewhat dangerous to use.

The reason you wouldn’t be able to do anything with straight JSON if you tried to get it with <script src> is that while it’s a valid JavaScript object, it’s just that: an object. It doesn’t have a name, or any other way to access it in the script. In fact, since the script has no other references to the new JSON object, it’s likely to just be immediately deleted (or “garbage collected”) by the script engine.

Application developers sometimes work around this problem by using a variation of JSON called JSONP, short for JSON with Padding. JSONP is similar to JSON, except that the data is wrapped in (or “padded with”) a JavaScript function call that’s usually specified by the client requesting the data. For example, if you make a request to a music catalog web service and specify that you want the returned data wrapped in the function “displayAlbumInfo,” the JSON you get back might look something like this:

displayAlbumInfo({"artist":"The Black Keys","album":"Brothers"});

All you have to do now is to implement a displayAlbumInfo function in your script code. Now when you point a <script src> tag at the JSONP-returning music service, your displayAlbumInfo callback function will automatically execute and you can do whatever you want with the returned JSONP data.

Read the whole chapter

To learn more about browser security principles, read the rest of Chapter 5: Browser Security Principles: The Same-Origin Policy (.pdf)

Just as in our previous discussion of JSON and “eval,” you have to trust the JSONP source not to return malicious script code to you, but there’s also another reason you might want to avoid JSONP. Let’s switch places for a minute and say that you’re the one who’s actually serving the JSONP data instead of the one who’s requesting it. You already know that the same-origin policy doesn’t apply to JSONP; that’s why you’re using it in the first place. But without the protection of the same-origin policy, there’s nothing to keep an attacker from getting the data either. If you’re not clear on how an attack like this would work, we’ll discuss it in more detail later in this chapter when we talk about cross-site request forgery. For now, just keep in mind that we recommend against serving data in JSONP form, except when that data is completely public and can safely be viewed by anybody.

Excerpted from Web Application Security: A Beginner’s Guide by Bryan Sullivan and Vincent Liu (McGraw-Hill; 2012) with permission from McGraw-Hill.

Web Application Security: A Beginner’s Guide

Authors: Bryan Sullivan and Vincent Liu

learn more about Web Application Security, A Beginner's Guide from publisher McGraw-Hill

This was first published in February 2012

Dig deeper on Web Browser Security

Pro+

Features

Enjoy the benefits of Pro+ membership, learn more and join.

0 comments

Oldest 

Forgot Password?

No problem! Submit your e-mail address below. We'll send you an email containing your password.

Your password has been sent to:

-ADS BY GOOGLE

SearchCloudSecurity

SearchNetworking

SearchCIO

SearchConsumerization

SearchEnterpriseDesktop

SearchCloudComputing

ComputerWeekly

Close