(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
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/.)
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
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
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
transparently forwarded to https://api.del.icio.us/v1/. The simplest way to set up
a proxy is with the
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
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
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);
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.
not uncommon among web browsers. The basis of this trick is that the
script tag doesn’t have to
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.
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
src attribute was already in
wide use before anyone started seriously thinking about the security
Now cast your mind back to the elephant example in Example 11-6. It includes this line:
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
documentation, Yahoo! promises that the representation of a
argument into a callback function named in the URI (here, it’s
formatImages). The resulting
When the client loads the HTML page, it fetches that URI and run
formatImage method. Great for our
application; not so great for the web browser. From a security
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
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!
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
The only example of JoD I’ve given so far has a hardcoded
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.
new tags to the DOM object representing the current HTML page. And
script is just another HTML tag.
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
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
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
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
representation you receive is immediately executed as
The underlying technique, of referencing a new object in a
src attribute, is safer when you
script isn’t the only HTML tag
that makes the browser load a representation. Other useful tags
frame. Google Maps uses
img tags rather than
XMLHttpRequest calls to fetch its map tile
just creates the
img tags and
lets the browser make requests for the images as a side
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
except it supports fewer of HTTP’s features, and instead of
expecting the server to send an XML representation, it expects a
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
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
To make a web service request I pass the URI of a resource
JSONscriptRequest object. The
addScriptTag method sticks a
script tag into the DOM. When
the browser processes its new tag, it makes a GET request to the
representation. I specified “callback=formatImages” in the URI’s
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
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