Skip to main content

Restricting Access to your AJAX Services

Posted by gmurray71 on August 2, 2006 at 11:32 AM PDT

Services like the XmlHttpProxy for Java are designed to return JavaScript that is evaluated on the client. Unfortunately, if you are not careful with the design of your services, JSONP techniques could be used to hijack your services. While I'm not saying JSONP is bad, I do highly recommend you carefully track, limit, or restrict access to your application's services to JavaScript clients. Here are some strategies for doing this.

  1. Token Based Restriction - Limit a client access to server-side resources by using tokens. Resources may include URLs, databases, web services, or domain objects which that service may access to complete a request. Tokens may be configured in a file or by using your server's built-in security features.
  2. Unique Hash / Session Based Restriction - When generating a page that accesses the target service you can create a unique hash or key for each client and restrict access based on the existence of the hash. The session management facilities of the servlet API may easily used to track whether or not a conversation has been established.
  3. URL Based Restriction - Based on the URL in which the JavaScript is executed you can restrict access to a service.
  4. Application Key Based Restriction - An application key is a flexible means of providing access to your service to a set of JavaScript clients.
  5. Content-Type / Authentication Based Restriction - You can restrict JavaScript clients outside of the domain from directly accessing your service by using XML possibly in combination with basic or digest authentication.

Let's look at restricting service access in more detail and how it is handled by the XmlHttpProxy for Java.

  1. Token Based Restriction

    The XmlHttpProxy
    and the XmlHttpProxyServlet which provides web applications access to the proxy were updated to restrict access based on tokens. A token or key is mapped to a set of parameters which include the service URLs, service API keys, XSL style sheets, and default values used by the XmlHttpProxy. Following is an example of the JSON based configuration file for the XmlHttpProxyServlet .

    {"xhp": {
        "version": "1.1",
        "services": [
            {"id": "yahoogeocoder",
             "url":"http://api.local.yahoo.com/MapsService/V1/geocode",
             "apiKey" : "appid=jmaki-key",
             "xslStyleSheet": "yahoo-geocoder.xsl",
             "defaultURLParams": "location=santa+clara,+ca"
            },
            {"id": "flickrtagsearch",
             "url":"http://www.flickr.com/services/rest/?method=flickr.photos.search",
             "apiKey" : "api_key=06d3805b73897217be9e0b532c85b15e",
             "xslStyleSheet": "flickr-search.xsl",
             "defaultURLParams": "tags=theKt"
            },
            {"id": "yahoosearch",
             "url":"http://api.search.yahoo.com/WebSearchService/V1/webSearch",
             "apiKey" : "appid=jmaki-key",
             "defaultURLParams": "query=jMaki"
            }
        ]
      }
    }

    Using token based restriction to resources allows you to consolidate what may be accessed and provide defaults. In the example above id is the key which is the token passed by a client to the XmlHttpProxyServlet along with some other parameters such as the location which is needed by the Yahoo Geocoder.

    The JavaScript client using token based access may appear as the one in the example below.

    var location = encodeURIComponent("location=sunnyvale ca");
    dojo.io.bind({
        url: "xhp?key=yahoogeocoder&urlparams=" + location,
        mimetype: "text/json",
        load : function(type, data) {                               
                alert("latitude=" + data.coordinates[0].latitude);
       }
    });

    Notice that the extra parameters (location in the case above) are encoded using the JavaScript encodeURIComponent function to ensure they are properly sent to the XmlHttpProxyServlet.

    Java EE provides role based security which you can use to restrict the server side resources such as EJB components, JDBC connections, or web services that your service may expose. For more details see the Java EE 5.0 Tutorial.

    Allowing JavaScript to directly configure parameters such as the URL accessed by the proxy or a query to a database could open yourself up to unauthorized access. Token based restrictions provides easy access to your service to JavaScript clients and it is the most flexible of the approaches for restricting access to your services. Token based restriction will not prevent users from outside your application domain from using your services but as in the case with the XmlHttpProxy it will prevent users or other applications in other domains from using the proxy to access services you did not intend for it to provide access to.

  2. Application Key based Restriction

    Yahoo commonly uses application level keys to give access to their
    vast set of services. This approach is pretty flexible in that it gives flexible means to access services. This level of key provides more coarse grained access which is more developer friendly. Below is an example of a call to the Yahoo Geocoder.

    http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=jmaki&results=1

    The URL parameter appid as "YahooDemo" is the application key in the example above. You can copy and paste the URL right into your browser or use curl to readily see the results.

    http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=jmaki&results=1&output=json&callback=showResults

    Setting the output to "json" will cause the service to return JSON based content. More importantly the callback parameter
    is set to the name of the method you want called. In essence if you call this from your JavaScript code you will need a global function showResults that takes a single argument. The results from Yahoo call may appear as:

    showResults({"ResultSet": {"type":"web", "totalResultsAvailable":318000, "totalResultsReturned":1, "firstResultPosition":1, "moreSearch":"...", "Result":[{"Title":"ajax: Project jMaki", "Summary":"... Project jMaki. jMaki is all about enabling Java developers to use JavaScript in their Java based applications as ... or a JSF component. jMaki uses the best parts of Java and ...", "Url":"https:\/\/ajax.dev.java.net\/","ClickUrl":"...", "DisplayUrl":"https:\/\/ajax.dev.java.net\/", "ModificationDate":1154242800, "MimeType":"text\/html", "Cache":{"Url":"...", "Size":"15905"}}]}})

    The sample code below will do a search and display an alert dialog with the summary of
    the first result.

    <script type="text/javascript">
        function showResults(searchResults) {
            alert(searchResults.ResultSet.Result[0].Summary);
        }
    </script>

    <script src="http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=jmaki&results=1&output=json&callback=showResults"
        type="text/javascript"></script>

    Using application keys allows a developer friendly means providing access to application services as the keys can be human readable used throughout a web application. It is not as strict and more based on the "honor" system as a key could be used in more than one application. The service provider can still track the usage and limit access if the application key is misused.

  3. URL based Restriction

    If you have included Google Maps in your application you will notice that it requires an API key as a parameter of the script URL. The API key is matched to the URL directory to which the map will be accessed.

    <script src="http://maps.google.com/maps?file=api&v=2&key=abcd123"
            type="text/javascript">
    </script>

    In the example above the key "abcd123" would be much longer key used to a domain name and directory that has permission to use Google Maps. The key "abcd123" for example would only unlock access to a web application accessed at the URL:

    http://javaserver.org/jmaki/

    Clients that attempt to access the Google Maps service from a URL other than http://javaserver.org/jmaki/ will be presented with an error dialog such as the one that follows.

    You can used the same technique to provide fine grained access to your services and track who uses your services. You would be responsible for generating, distributing, and managing the the URL keys based and checking them with each access to your service using headers passed in with the request such as the referrer header.

    Restricting access based on URLs allows you to restrict who can access your service, limit the number of accesses, and track usage. This approach can make it more difficult for developers using the service as it requires the developer to get new keys on a per URL basis.

  4. Hash / Session Based Restriction

    One other issue I wanted to avoid with the XmlHttpProxy was to prevent cross domain access to the XmlHttpProxyServlet . It would not make sense to expose the proxy service outside the domain as it would be essentially providing a free service that could be misused. I initially considered creating a unique hash for the page which accessed the service and pass it as a header/cookie to restrict access to service. I realized there was a simpler way to do this by using the built in functionalities of the servlet API using the HttpSession API. The Java servlet code is as follows:

      HttpSession session = request.getSession(false);
      if (session == null) {
          response.setStatus(HttpServletResponse.SC_FORBIDDEN);
          return;
      }

    Placing the code above will in essence stop direct access to the XmlHttpProxyServlet from clients in other domains.

    How it works

    A servlet/Java EE web container by default creates a HttpSession when a user navigates to any page of your application including the page containing the service. The service will look for the existence of the HttpSession, find it, and then provide access to the service.
    Clients from another domain attempting to directly access the service, using techniques such as JSONP techniques, will not have established an HttpSession and will be returned an HTTP 403 "Forbidden" error.

    One limitation of this technique is that it does not 100% guarantee that clients from other domains designed to use other means of initiating an HttpSession in order to access your service (which I will not detail here) however, general misused can be avoided. Another limitation of this technique is that HttpSession tracking will need to be enabled and the session must be still alive for this technique to work.

  5. Content-Type / Authentication Based Restriction

    You can design your services to provide different options in a similar way. It is recommended to use the method Yahoo services use by providing an optional output parameter of the URL as seen below.

    http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=jmaki&results=1&output=json&callback=showResults

    In the example above the returned data is in JSON format. Not specifying an output parameter in the URL will result XML formatted output. The Yahoo Geocoder does not provide an option for JSON output. Originally, the Yahoo Geocoder was accessible to JSONP but later the return content type was restricted to XML after the service was severely misused.

    You can restrict access to your services to prevent direct JSONP access in the same way the Yahoo Geocoder by only providing XML formated output. This technique forces JavaScript clients to use a proxy like the XmlHttpProxy to access your service.

    You may choose to use HTTP basic or HTTP digest authentication. The servlet API provides built in support for securing your services or other web resources. The servlet API provides built in support for securing your services or other web resources. The APIs you would use to secure your services are the same APIs available with the Java EE platform. For more details on setting up HTTP basic and digest authentication see the Java EE 5.0 Tutorial or some security examples provided by Jason Hunter on Servlets.com.

    Limiting the content type and/or requiring authentication is a usefull strategy if you would like to restrict access to your services small set users or domains. Using this authenication should be considered if you are allowing users to update data provided by your user to provide some level of accountability and update tracking. Limiting the content type and/or requiring authentication are the most strict form restricting access to your services. Consider your clients and motivations before using these techniques.

We have reviewed many ways to control access to a service to AJAX requests. Each technique discussed in this blog has its' benefits and pain points. The techniques described in this blog are not mutually exclusive, you may choose to restrict access using a combination of technqiques based on your user cases and client needs.

Are you using a techniques to restrict access to your services not discussed here? If so please share.



Related Topics >>