Wednesday, December 20, 2006

CSRF protection for the AJAX area of web applications

I'll be using following terms throughout the article,

  • AJAX area: Server side scripts which are mainly designed to process requests generated by client side scripts (AJAX)
  • Non AJAX area: Other server side scripts
  • Application: Sometimes the term will be used to refer to the JavaScript that gets executed.

In an AJAX application, the user loads a normal HTML page in his browser. This page includes JavaScripts that later fire AJAX requests and fetch response from the server asynchronously.

AJAX request in some sense looks just like a normal HTTP request. However, there are few extra capabilities that AJAX enjoys. The central idea used in this technique is the AJAX's capability of adding request headers in the request.

Many posts in the security community have indicated that having method names etc. in the request headers expose the internal details of the APIs that the server supports. But, the request headers can be advantageous as far as CSRF prevention is concerned.

"If EVERY INCOMING REQUEST IN THE AJAX AREA IS REQUIRED TO INCLUDE A REQUEST HEADER, CSRF CAN BE PREVENTED."

This is considering the fact that only way to add a request header is by use of XMLHttp object (i.e. only AJAX has this capability! *, **)

Lets consider following example to understand this clearly.

The website which uses AJAX heavily, is divided into two sections AJAX, Non AJAX. NonAJAX area is prevented from CSRF using other techniques. ALL AJAX requests originating from the application, include a special request header that looks like following, X-AJAX_AREA: true (using setRequestHeader()). Every server side script in the AJAX area, serves the requests ONLY if the requests contain this special header. This way, we know for sure that whatever requests are served in this area are legitimate, and generated by the aplication itself.

Therefore CSRF risks can be minimized to a great extent.


Notes:

  1. If your site has XSS, this technique won't help.
  2. This does not prevent other injection attacks.
  3. Gmail is an example of application which uses AJAX heavily.
  4. This technique works only in the AJAX area of the application


* Written to the best of my knowledge, any criticism is highly encouraged.

** I do not know if this is possible with other technologies like flash. But hope something like this is no more possible.

Tuesday, December 05, 2006

Use of time delay technique for effective CSRFs

I read Jeremiah Grossman's article on Browser Port Scanning without JavaScript.
One point to note is that this is based on the time difference that is observed when

  1. A host is up
  2. A host is down

One of the techniques of port scanning using javascript also relies on this time difference.

Now look at comment that says "The purpose of CSRF is to perform actions on behalf of the current user but this user must be authenticated first. Otherwise, there is no point in doing whatsoever." here.

Is it possible for an attacker to determine if the victim has logged in? YES it is definitely possible. Again we rely on the time difference technique. Just observe what sites throw at you when you request a private page without having authenticated. All of them will either display an error message or a login form.

Now if you see the time taken when you are logged in vs when you are not logged in, you will see a considerable difference (It depends on what private page you request).

Using this phenomenon, attacker can always determine if the victim has logged in.

Following code shows how this can be done,
<body>
<script>
function loaded()
{
var time = new Date();
var t2 = time.getTime();
alert(t2- t1);
}
var time = new Date();
var t1 = time.getTime();
</script>
<iframe src="http://www.orkut.com/News.aspx" onload="loaded()">
</iframe>
</body>

On news.aspx page without logging in, I got following readings

7391, 6938, 6453

After logging in,

4453, 5844, 4375, 4359, 4375

It should be noted that these readings may depend on,

  1. Network speed
  2. Number of cacheable objects on the page (And therefore might vary significantly on every subsequent run)

Therefore it is necessary to select a private page that preferably has least number of cacheable objects. Also, the time taken for private-page load and login-page load should not be comparable.

As I see it, many such things are possible if we study the behavior of web applicaions.