Transparency in Ajax Applications - Part 2/Page 2
Transparency in Ajax Applications - Part 2
Overly Granular Server API
The lack of proper authorization in the previous section is really just a specific case of a much broader and more dangerous problem: the overly granular server API. This problem occurs when programmers expose a server API and assume that the only consumers of that API will be the pages of their applications and that those pages will always use that API in exactly the way that the programmers intended. The truth is, an attacker can easily manipulate the intended control flow of any client-side script code. Let's revisit the online music store example from Chapter 1, "Introduction to Ajax Security."
We will start with the debugger Firebug for Firefox. Firebug will display the raw HTML, DOM object values, and any currently loaded script source code for the current page. It will also allow the user to place breakpoints on lines of script, as we do in Figure 6-9.
You can see that a breakpoint has been hit just before the call to the
checkCredentials function. Let's step over this line, allow the client to call
checkCredentials, and examine the return value (see Figure 6-10).
Figure 6-10 Examining the return value from checkCredentials
Unfortunately, the username and password we provided do not appear to be valid. The value of the
authenticated variable as returned from
checkCredentials is false, and if we allow execution of this code to proceed as-is, the page will alert us that the credentials are invalid and then exit the
purchaseSong function. However, as a hacker, this does us absolutely no good. Before we proceed, let's use Firebug to alter the value of
authenticated from false to true, as we have done in Figure 6-11.
By editing the value of the variable, we have modified the intended flow of the application. If we were to let the code continue execution at this point, it would assume (incorrectly) that we have a valid username and password, and proceed to retrieve the price of the selected song. However, while we have the black hat on, why should we stop at just bypassing authentication? We can use this exact same technique to modify the returned value of the song price, from $.99 to $.01 or free. Or, we could cut out the middleman and just use the Console window in Firebug to call the
downloadSong function directly.
Figure 6-11 The attacker has modified the value of the authenticated variable from false to true.
In this example, all of the required steps of the transaction—checking the user's credentials, ensuring that she had enough money in her account, debiting the account, and downloading the song—should have been encapsulated as one single public function. Instead of exposing all of these steps as individual methods in the server API, the programmers should have written a single
purchaseSong method that would execute on the server and enforce the individual steps to be called in the correct order with the correct parameter values. The exposure of overly-granular server APIs is one of the most critical security issues facing Ajax applications today. It bears repeating: Never assume that client-side code will be executed the way you intend—or even that it will be executed at all.
The issue of inappropriately storing session state on the client is nothing new. One of the most infamous security vulnerabilities of all time is the client-side pricing vulnerability. Client-side pricing vulnerabilities occur when applications store item prices in a client-side state mechanism, such as a hidden form field or a cookie, rather than in server-side state. The problem with client-side state mechanisms is that they rely on the user to return the state to the server without tampering with it. Of course, trusting a user to hold data as tantalizing as item prices without tampering with it is like trusting a fiveyear-old to hold an ice cream cone without tasting it. When users are capable of deciding how much they want to pay for items, you can be certain that free is going to be a popular choice.
For example, suppose that the server exposes an
AddItem function to add an item to the shopping cart and a second function,
CheckOut, to check out. This is a well-defined API in terms of granularity, but if the application relies on the client-side code to keep a running total of the shopping cart price, and that running total is passed to the CheckOut function, then the application is vulnerable to a client-side pricing attack.