AJAX In Action [136]
Licensed to jonathan zheng Policing access to Ajax data streams 273 Fortunately, HTTP is quite a rich protocol, and the XMLHttpRequest object gives us a good level of fine-grained control over it. When a request arrives on the server, we have access to a range of HTTP headers from which we can infer things about the origin of the request. Filtering HTTP requests For the sake of providing concrete examples, we’ll use Java code here. Other server-side technologies offer similar ways to implement the techniques that we are describing, too. In the Java web application specification, we can define objects of type javax.servlet.Filter, which intercept specific requests before they are processed at their destination. Subclasses of Filter override the doFilter() method and may inspect the HTTP request before deciding whether to let it through or forward it on to a different destination. Listing 7.5 shows the code for a simple security filter that will inspect a request and then either let it through or forward it to an error page. Listing 7.5 A generic Java security filter public abstract class GenericSecurityFilter implements Filter { protected String rejectUrl=null; public void init(FilterConfig config) throws ServletException { rejectUrl=config.getInitParameter("rejectUrl"); b Configure reject URL } public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (isValidRequest(request)){ c Check request validity chain.doFilter(request, response); }else if (rejectUrl!=null){ d Forward to reject URL RequestDispatcher dispatcher =request.getRequestDispatcher(rejectUrl); dispatcher.forward(request, response); } } protected abstract boolean isValidRequest(ServletRequest request); public void destroy(){} } Licensed to jonathan zheng 274 CHAPTER 7 Security and Ajax The filter is an abstract class, defining an abstract method isValidRequest() that inspects the incoming request object before passing a verdict. If the method fails c, it is forwarded to a different URL d, which is defined in the configuration file for the web application b, which we’ll look at shortly. This filter provides us with considerable flexibility in defining a concrete subclass. We can adapt it to more than one security strategy. Using the HTTP session One common approach is to create a token in the user’s HTTP session when she logs in and check for the existence of that object in session during subsequent requests before performing any other actions. Listing 7.6 demonstrates a simple filter of this type. Listing 7.6 Session token-checking filter public class SessionTokenSecurityFilter extends GenericSecurityFilter { protected boolean isValidRequest(ServletRequest request) { boolean valid=false; HttpSession session=request.getSession(); if (session!=null){ UserToken token=(Token) session.getAttribute('userToken'); if (token!=null){ valid=true; } } return valid; } } This technique is commonly used in conventional web applications, typically forwarding to a login screen if validation fails. In an Ajax application, we are free to return a much simpler response in XML, JSON, or plain text, which the client could respond to by prompting the user to log in again. In chapter 11, we discuss a fuller implementation of such a login screen for our Ajax Portal application. Using encrypted HTTP headers Another common strategy for validating a request is to add an additional header to the HTTP request and check for its presence in the filter. Listing 7.7 shows a second example filter that looks for a specific header and checks the encrypted value against a known key held on the server. Licensed to jonathan zheng Policing access to Ajax data streams 275 Listing 7.7 HTTP header-checking filter public class SecretHeaderSecurityFilter extends GenericSecurityFilter