Transparency in Ajax Applications - Part 2/Page 2
[previous] [next]
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."
The intended flow of this code is straightforward. First the application checks the user's username and password, then it retrieves the price of the selected song and makes sure the user has enough money in his account to purchase it. Next, it debits the user's account for the appropriate amount, and finally it allows the song to download to the user's computer. All of this works fine for a legitimate user. But let's think like our hacker Eve would and attach a JavaScript debugger to the page to see what kind of havoc we can wreak.
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.
Figure 6-9 Attaching a breakpoint to JavaScript with Firebug
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.
Session State Stored in Javascript
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.
While this issue is not new to Ajax, Ajax does add a new attack vector: state stored in client-side JavaScript variables. Remember the code from the online music store:
By storing the song price in a client-side JavaScript variable, the application invites attackers to modify the value and pay whatever they like for their music. We touched on this concept earlier, in the context of making the server API too granular and allowing an attacker to manipulate the intended control flow. However, the problem of storing session state on the client is separate from the problem of having an API that is too granular.
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.
[previous] [next]
URL: