O'Reilly logo

RESTful Web Services by Sam Ruby, Leonard Richardson

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Subverting the Browser Security Model

That’s a provocative title but I stand by it. A web browser enforces a general rule that’s supposed to prevent it from using code found on domain A to make an HTTP request to domain B. I think this rule is too strict, so I’m going to show you two ways around it: request proxying and JoD. I’m also going to show how these tricks put you at risk by making you, the Ajax programmer, accept responsibility for what some foreign server does. These tricks deserve to be regarded as cheats, because they subvert rather than fulfill the web browser’s intentions. They often make the end user less secure than if his browser had simply allowed domain A’s JavaScript to make an HTTP request to domain B.

There is a secure method of getting permission to make foreign web service calls in your JavaScript applications, which is to ask for the permission by calling:


(There’s also an insecure method, which is to have your users use Internet Explorer with the security settings turned way down.)

If your script is digitally signed, the client’s browser shows your credentials to the end user. The end user makes a decision whether or not to trust you, and if he trusts you he gives you permission to make the web service calls you need to make. This is similar to the technique I mentioned in Chapter 8, where an untrusted web service client was trying to gain the end user’s trust. The difference here is that the untrusted web service client is running inside the end user’s trusted web browser.

There are two problems with the secure method. The first is that, as you might have guessed from the name netscape.security.PrivilegeManager, it only works in Mozilla, Firefox, and Netscape-like browsers. The second is that it’s quite painful to actually get a signed script set up. Once you do get one set up, you find you’ve stored your HTML files in a signed Java archive file, and that your application is off the Web! Search engines won’t pick up your HTML pages, and you’ll only be able to address them through a weird jar: URI like jar:http://www.example.com/ajax-app.jar!/index.html.

And that’s the right solution. As you can tell, this is an immature field. Until recently, web services weren’t popular enough for people to seriously think about these problems. Though the hacks described below are potentially dangerous, their inventors meant no harm. They were motivated only by zeal for the enormous possibilities of in-browser web service clients. The challenge is to come up with ways of getting the same functionality without sacrificing security, adding too much complexity, or moving Ajax applications out of view of the Web. The W3C is working on this problem (see “Enabling Read Access for Web Resources” at http://www.w3.org/TR/access-control/.)

Although I’m focusing again on JavaScript applications, Java applets and Flash also run under security models that prevent them from sending data to foreign servers. The request proxying trick, described below, works for any kind of Ajax application, because it involves work on the server side. As its name implies, the JoD trick is JavaScript-specific.

Request Proxying

You’re running a site, example.com, serving up Ajax applications that try to make XMLHttpRequest requests against yahoo.com. Naturally your clients’ web browsers will complain. But what if they never made a request to yahoo.com? What if they made requests to example.com, which you handled by making your own, identical requests to yahoo.com without telling the client?

Welcome to the request proxy trick, well described in Yahoo’s document “Use a Web Proxy for Cross-Domain XMLHttpRequest Calls”. In this trick, you set aside part of the URI space on your server to simulate the URI space on some other server. When you get a request to a URI in that space, you send it along without alteration to the foreign server, and then pipe the response right back to the client. From the client’s point of view, it looks like you’re providing someone else’s web service. Really, you’re just filing the domain names off their HTTP responses and replacing them with your own.

If you’re using Apache and have mod_proxy installed, the simplest way to set up a proxy is in the Apache configuration. If you also have mod_ssl installed, you can enable SSLProxyEngine and proxy HTTPS requests. So long as you have mod_ssl installed, you can even proxy HTTPS requests from an HTTP server: perhaps http://example.com/service/ is proxied to https://service.com/. Of course, this destroys the security of the connection. Data is secure between the proxy and your site, but not between your site and the end user. If you do this you’d better tell the end user what you’re doing.

Let’s say you want to make the del.icio.us Ajax application, given above, work from your site at example.com. You can set up a proxy so that all URIs beneath https://example.com/apis/delicious/v1/ are transparently forwarded to https://api.del.icio.us/v1/. The simplest way to set up a proxy is with the ProxyPass directive, which maps part of your URI space onto a foreign site’s URI space (see Example 11-10).

Example 11-10. Apache configuration with ProxyPass

SSLProxyEngine On
ProxyRequests Off # Don’t act as an open proxy.
ProxyPass /apis/delicious/v1 https://api.del.icio.us/v1/

A more flexible solution is to use a rewrite rule with the [P] flag. This gives you the full power of regular expressions to map your URI-space onto the foreign site’s. Example 11-11 shows a rewrite rule version of the del.icio.us API proxy:

Example 11-11. Apache configuration with rewrite rules

SSLProxyEngine On 
ProxyRequests Off # Don’t act as an open proxy. 
RewriteEngine On RewriteRule ^apis/delicious/v1/(.*)$ https://api.del.icio.us/v1/$1 [P]

With a setup like one of those two, you can serve the Ajax application defined in Example 11-1 through Example 11-5 from your own domain, without triggering browser security warnings. All you have to do is change this (from Example 11-4):

request.open("GET", "https://api.del.icio.us/v1/posts/recent",
             true, username, password);

to this:

request.open("GET", "https://example.com/apis/delicious/v1/posts/recent", 
             true, username, password);

Most Apache installations don’t have mod_proxy installed, because an open HTTP proxy is a favorite tool for spammers and other lowlife who want to hide their tracks online. If your web server doesn’t have built-in proxy support, you can write a tiny web service that acts as a transparent proxy, and run it on your server. To proxy del.icio.us API requests, this web service might be rooted at apis/delicious/v1. It would pass any and all HTTP requests it received—HTTP headers and all—to the corresponding URI beneath https://api.del.icio.us/v1/. Yahoo! provides a sample proxy service, written in PHP, hardcoded to access the yahoo.com web services. You can model your own proxy service after that one.

Even when your proxy is properly configured, when it only proxies requests for a very small subset of the Web, there is danger for you and your end users. When you set up a proxy for Ajax clients, you’re taking responsibility in your users’ eyes for what the other web site does. The proxy trick sets you up as the fall guy for anything bad that happens on the other site. You’re pretending what the other site is serving comes from you. If the web service crashes, cheats the end user, or misuses his personal data, guess what: it looks like you did those things. Remember, in an Ajax application the end user only sees your GUI interface. He doesn’t necessarily know his browser is making HTTP requests in the background, and he certainly doesn’t know that his requests to your domain are being proxied to another domain. If his web browser knew that was going on, it would step in and put a stop to it.

The proxy trick also sets you up as the fall guy for the requests your clients make. Your clients can make any web service request they like and it’ll look like you’re the cause. Depending on the nature of the web service this may cause you embarrassment or legal exposure. This is less of a problem for web services that require separate authorization.

JavaScript on Demand

It’s rare for a human being to demand JavaScript, except in certain design meetings, but it’s not uncommon among web browsers. The basis of this trick is that the HTML script tag doesn’t have to contain hardcoded JavaScript code. It might just have a src attribute that references code at another URI. A web browser knows, when it encounters a script tag, to load the URI in the src attribute and run its contents as code. We saw this in Example 11-6, the JSON example that does a Yahoo! image search for pictures of elephants.

The src attribute is traditionally used like C’s #include or Ruby’s require: to load in a JavaScript library from another URI. Example 11-12, reprinted from Chapter 2, shows this.

Example 11-12. Including a JavaScript file by reference

<!-- In a real application, you would save json.js locally
     instead of fetching it from json.org every time. --> 
<script type="text/javascript" src="http://www.json.org/json.js"></script>

As you can see, the URI in the src attribute doesn’t have to be on the same server as the original HTML file. The browser security model doesn’t consider this insecure because... well, near as I can figure, because the src attribute was already in wide use before anyone started seriously thinking about the security implications.

Now cast your mind back to the elephant example in Example 11-6. It includes this line:

<script type="text/javascript"
?appid=restbook&query=baby+elephant&output=json&callback=formatImages" />

That big long URI doesn’t resolve to a standalone JavaScript library, the way http://www.json.org/json.js does. If you visit it in your web browser you’ll see that URI’s representation is a custom-generated bit of JavaScript. In its developer documentation, Yahoo! promises that the representation of a resource like this one is a snippet of JavaScript code. Specifically, a snippet of JavaScript code that passes a data structure as the only argument into a callback function named in the URI (here, it’s formatImages). The resulting JavaScript representation looks something like this:


When the client loads the HTML page, it fetches that URI and run its body as JavaScript, incidentally calling the formatImage method. Great for our application; not so great for the web browser. From a security perspective this is just like JavaScript code that uses XMLHttpRequest to get data from the Yahoo! web service, and then calls formatImage on the result. It bypasses the browser security model by making the HTTP request happen as a side effect of the browser’s handling of an HTML tag.

JoD switches the traditional roles of a script embedded in an HTML page and a script included via <script src="...">. Your web browser requests a web service URI, thinking it’s just a JavaScript library that application code in the HTML page will eventually call. But the library function is the one defined locally (it’s formatImage), and the application code that calls that function is coming from a foreign site.

If you specify no callback in the URI when calling the Yahoo! web service, you get a “JavaScript” file containing nothing but a JSON data structure. Including this file in a script tag won’t do anything, but you can fetch it with a programmable HTTP client (like XMLHttpRequest, or the Ruby client from way back in Example 2-15) and parse it as data:


Dynamically writing the script tag

The only example of JoD I’ve given so far has a hardcoded script tag. The URI to the web service resource is fixed in stone, and if the end user wants to see baby penguins instead of baby elephants he’s just out of luck.

But one of the things you can do with JavaScript is add brand new tags to the DOM object representing the current HTML page. And script is just another HTML tag. You can use JavaScript to write a customized script tag into the document, and get the browser to load the URI mentioned in its src attribute as a side effect of the script processing. The browser allows this even if the src URI points to a foreign domain. That means you can use JavaScript to make requests to any URI that serves more JavaScript, and run it.

This works, but it’s a hack on top of a hack, and a security problem on top of a security problem. In fact, from a security perspective this is worse than using XMLHttpRequest to get data from a foreign site. The worst XMLHttpRequest will do is make an HTTP request and parse some XML into a tree-like data structure. With JoD you make an HTTP request and run previously unseen JavaScript code as though it was part of your original program.

You and your end user are completely at the mercy of the service you’re calling. Instead of JavaScript that does what you want, a malicious web service might decide to serve JavaScript that steals whatever cookies your domain set for this user. It might serve code that runs code as promised but also creates pop-up windows full of obnoxious ads. It might do anything at all. And since Ajax hides the HTTP request-response cycle from the end user, it looks like your site is responsible!

Now, maybe you trust a brand-name site like Yahoo! (unless it gets cracked), but you probably don’t trust Mallory’s House of Web Services. And that in itself is a problem. One of the nice things about the Web is that you can safely link to Mallory even if you don’t trust her, don’t have her permission, and think she’s wrong about everything. A normal web service client can make calls to Mallory’s web service, and examine the representation before acting on it in case she tries any trickery. But when the client is serving executable code, and the web service requested it through a hack that runs the code automatically, you’re reduced to operating on blind trust.

JoD is not only sketchy from a security standpoint, it’s a lousy tactic from a REST standpoint, because it forces you to use a crippled client. XMLHttpRequest supports all the features of HTTP, but with JoD you can only make GET requests. You can’t send request headers, see the response code or headers, or handle representation formats other than JavaScript code. Any representation you receive is immediately executed as JavaScript.

The underlying technique, of referencing a new object in a src attribute, is safer when you use it to grab resources other than custom-generated JavaScript. script isn’t the only HTML tag that makes the browser load a representation. Other useful tags include img and frame. Google Maps uses img tags rather than XMLHttpRequest calls to fetch its map tile images. Google’s JavaScript code doesn’t make the HTTP requests. It just creates the img tags and lets the browser make requests for the images as a side effect.

Library support

Jason Levitt has written a JavaScript class called JSONscriptRequest that makes JoD easy (http://www.xml.com/pub/a/2005/12/21/json-dynamic-script-tag.html). This class works sort of like XMLHttpRequest, except it supports fewer of HTTP’s features, and instead of expecting the server to send an XML representation, it expects a snippet of JavaScript.

Example 11-13 shows a dynamic implementation of the image search Ajax application. The first part should be familiar if you’ve looked at the other Ajax applications in this chapter.

Example 11-13. Dynamic Yahoo! image search Ajax application

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
<!--An Ajax application that uses dynamic SCRIPT tags to interactively
    fetch data from Yahoo! Web Services and call predefined functions
    on that data.-->

<head><title>Javascript Yahoo! JSON - Dynamic</title></head>
<h1>Javascript Yahoo! JSON example with dynamic SCRIPT tags</h1>

<form onsubmit="callYahoo(); return false;">
 What would you like to see? <input id="query" type="text" /><br />
 <input type="submit" value="Fetch pictures from Yahoo! Image Search"/>

<div id="images">

<script type="text/javascript">
function formatImages(result)
  // First clear out any old images.
  var images = document.getElementById("images");
  while (images.firstChild) 

  items = result["ResultSet"]["Result"];
  for (var i = 0; i < items.length; i++)
    image = items[i];

    // Create a link
    var link = document.createElement("a");
    link.setAttribute("href", image["ClickUrl"]);

    // Put a thumbnail image in the link.
    var img = document.createElement("img");
    var thumbnail = image["Thumbnail"];
    img.setAttribute("src", thumbnail["Url"]);
    img.setAttribute("width", thumbnail["Width"]);
    img.setAttribute("height", thumbnail["Height"]);
    img.setAttribute("title", image["Title"])

Here’s where this application diverges from others. I include Jason Levitt’s jsr_class.js file, and then define the callYahoo function to use it (see Example 11-14). This is the function triggered when the end user clicks the submit button in the HTML form above.

Example 11-14. Dynamic Yahoo! image search Ajax application continued

<script type="text/javascript" src="jsr_class.js"></script>

<script type="text/javascript">
function callYahoo()
  var query = document.getElementById("query").value;
  var uri = "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch" +
            "?query=" + escape(query) + 
  var request = new JSONscriptRequest(uri);


To make a web service request I pass the URI of a resource into a JSONscriptRequest object. The addScriptTag method sticks a new script tag into the DOM. When the browser processes its new tag, it makes a GET request to the foreign URI, and runs the JavaScript that’s served as a representation. I specified “callback=formatImages” in the URI’s query string, so Yahoo! serves some JavaScript that calls my formatImages function on a complex data structure. You can serve this Ajax application from anywhere, and use it to search for anything on Yahoo!’s image search, without triggering any browser warnings.

The Dojo library makes the script trick easy by providing a dojo.io.SrcScript transport class that uses it. It also provides a dojo.io.IframeIO class which uses a similar trick involving the iframe tag. This trick also requires cooperation from the server, but it does have the advantage that it doesn’t automatically execute the response document as code.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required