Published: 01 Nov 2007
| Ajax, Java and other dynamic application coding methods have pulled computing power over to the client, introducing new risks and resurrecting old ones.
GETTING CLOSER TO AJAX
Ajax apps are not Web services, RESTful or otherwise, that are designed for consumption by other software. Web-based apps are functionally designed to be experienced via a browser. Securing browser-based applications requires securing the user--who wants to protect his private data--and the application, which wants to secure user data and its code. In the context of an Ajax app, it's essential to prevent private data from leaking from the client to the server, and that an application user's data does not leak from the server to a client. Also, sensitive information from the server should not be passed to any clients.
| NEW THREATS, SAME AS THE OLD THREATS
In Writing Secure Code, authors Michael Howard and David LeBlanc identify two principles of secure applications: "All input is evil until proven otherwise," and "Data must be validated as it crosses the boundary between untrusted and trusted environments."
In the context of a Web application, this means any data passed from a client's browser to a server must be validated before use in any context. There are three general uses for user-supplied data: it's stored in a database through a SQL query; it's used as a value in a calculation; or it's rendered as output back to the user.
Users, meanwhile, can submit data to a server in two ways: URI-encoded values--either in the querystring or as the entity body of an HTTP POST--or HTTP headers, either through a cookie or other HTTP header.
Nothing about Ajax changes these in any way. Ajax applications do not use user-supplied data in fundamentally new ways; they may render the output back as an HTML snippet instead of a full-formed HTML page, and they may perform calculations on the data on the client instead of on the server, but they are still either storing the data, performing a calculation using it, or rendering it.
Likewise, the XMLHttpRequest object that is the backbone of asynchronous processing is still just a mechanism for sending HTTP requests and receiving HTTP responses, which means data is passed to the server in the same ways it always has. "There is nothing new in the field of security; input validation is still the only major concern," says Billy Hoffman, lead researcher at SPI Dynamics.
With Ajax applications, content is often injected into a page in such a way that "view source" is meaningless. When an application uses the XMLHttpRequest object to send an asynchronous request to the server, the results are often added into the content through the use of the innerHTML property of DOM elements. For example:
| JSON, XML and serialized data. While there are only two ways a browser submits data to a server--still true with Ajax applications--there are important changes to representations of the data (see "Breaking Java," below). Historically, data transmitted through these vectors were name/value pairs, where the name and the value were represented as simple scalars, or arrays of scalars. For example:
There are Ajax applications, though, that don't represent the data this way. Instead of posting a collection of URI-encoded data, they might post a single name/value pair, using some form of serialized data representation. Here's the same POST, but with JSON serialization:
| Now, the server-side code has a different kind of validation problem, one that involves two steps: de-serialization of the data, followed by property-by-property validation of individual values. JSON isn't the only option for this kind of data, either. XML gets a fair amount of usage for data serialization, and now YAML (YAML Ain't Markup Language) as well (though mostly in Rails-based sites). There is also the rising tide of microformats, or custom data syntaxes that maximize efficiency of the representation at the expense of creating custom parsers for each syntax. In any of these cases, server-side validation now has two problems instead of one, and the complexity is a little greater as a result.
| STICK TO FUNDAMENTALS
Do Ajax applications even require new security solutions? The problem still comes down to validating user-provided input, and ensuring that whatever is sent to the user conforms to some valid representation format. The user-provided input might take on slightly different shapes in an Ajax world (such as serialized JSON), and responses back to the user might not be fully formed HTML (they could be serialized XML or JSON). These changes imply complexity, but not an overarching change in security; solutions remain relatively the same.
Scrubbing user input, validating system output. Regardless of the mechanisms by which data reaches a server, there are only three things an application will do with it: store, modify or render it. Server-side validation should be specific to how the data will be used: SQL scrubbing, type enforcement and HTML encoding, respectively. Sometimes a piece of data will be used in multiple ways during a single request, and it follows that each appropriate type of validation should be performed.
We can categorize potential system outputs four ways:
| THREAT MITIGATION TECHNIQUES
Since there are new vectors by which user data can arrive at the server, and several new ways for data to reach the client, developers need to expand the scope of known threat mitigation techniques. A comprehensive plan will include complete two-way data validation, client-side and server-side enforcement, and a rigorous testing harness. It should go without saying (but unfortunately still doesn't) that automated testing is the most fundamental part of any security infrastructure.
Standardized and customized data (de)serializers. If you are using structured data, make sure you have an appropriate parser for the syntax (standard parsers are available for all popular syntax). If using XML, create or use an existing schema that can be used to validate document structure and content. Many microformats have such schemas, and you should enable your XML library's validation for any inbound or outbound data.
| Modern templating engines. Most modern Web development platforms provide a templating engine that can automatically HTML-encode any dynamic data being interpolated into the template. Some examples:
Some even have a way to globally escape all rendered values unless specifically asked otherwise. Your code should take advantage of these tools as much as possible, only allowing unescaped HTML to be rendered if it was generated by your application directly, or via parsing a markup language.
Testing, monitoring and reporting. Finally, take advantage of the testing framework provided by your development platform. Perform unit testing on each security layer, ensuring that data validation and representation validation work with known examples of potential threats as test input. Perform functional testing and use some kind of user-spoofing testing technique to ensure the chain from browser to server and back. Make sure to run those tests often, locally and in a continuous integration environment.
HAPPY AND HOLISTIC
Organizations should take a comprehensive, holistic approach to application security by using validation methods on both sides of the untrusted boundary. This comprehensive approach needs to include thorough testing of the server and client-side logic. You need to understand how to debug Ajax apps using tools like FireBug, the IE Developer Toolbar and others.
As long as you adhere to primary rules of Web security--"All input is evil until proven otherwise," and "Data must be validated as it crosses the boundary between untrusted and trusted environments"--then Ajax shouldn't impact the security of the application.