May 12, 2007 - 15:47 UTC - Tags: XSRF security
There has been a lot of writing about Cross-site request forgeries (XSRF/CSRF) lately. I've read numerous articles on how this could be used to capture home routers or create false online-banking transactions. In this post I'll discuss some techniques for protecting your website against XSRF.
What is XSRF?If you don't know what XSRF is, I suggest you read
this wikipedia article. XSRF exploits the fact that a user can reach a website (because he's behind a firewall or logged in to a site), that the attacker cannot attack directly. If the attacker can trick the user into running a malicious script, he can force the users browser to act on his behalf.
A typical XSRF scenarioThe user sits on his home computer surfing the internet. He visits a malicious site, which runs some javascript on the users behalf. This script creates a form which it posts against the users home router. The form contains the standard username, password and IP-address of home routers from the user's ISP. The router cannot be reached from the internet, but the user is sitting in the same subnet as the router, and the router is accessible from the user's computer. Once the first form has been posted, the malicious script creates a second form, which tries to change the router's DNS to a malicious DNS. If this is successful, the attacker will have full control over what websites will be returned when the user enters an address in his browser, e.g. the attacker can return a fake banking site even though the user wrote the correct URL for his online-banking site in the browser (the user would get messages about untrusted SSL certificates, but most users blatantely ignore the messages).
It is important to understand that these attacks are blind, meaning the attacker only controls the user's browser indirectly and cannot always see if the XSRF was successful or not.
Protective measuresTo be able to protect a web page from XSRF, the web server needs to check that the requests are legit. This means that it needs some measure to check that the request actually came from the corresponding form in the application.
1. The referer headerSince the attacker does not directly control the user's browser, the referer header is actually a posibility. But some users disable the referer header because it leaks information when users click on links to other sites.
2. Unique identifiersThe second option is to include a unique identifier for each user. When the user opens a form and posts it back the server, the identifier sent to the user in when opening the form, must be included when posting back. If it is different or not present, the post is rejected.
Some people tend to think that using the session identifier for this purpose, is a good idea. If XSRF was the only security concern, I would agree, but using the session identifier directly contradicts the idea of HttpOnly-cookies (where the session id is protected against cookie-stealing by not being accessible from javascript).
Creating unique identifiers is easy, and instead of using the session identifier directly, we can use the fact that the user has a session to help creating and checking the identifier. We can use hash-function (md5 or sha1) in combination with a timestamp and a secret password/key. We create our identifier like this:
id = hash_function(secret_key + timestamp_in_milliseconds)
We put this identifier in the users session, and we then include this value in every form we send to the user. Checking the identifier when receiving a post is now trivial, and we do not expose the session identifier to javascript.
The protective measure described will not apply to GET requests, only POST requests. But if you are allowing GET requests to alter data in your application, your are misusing the semantics of the HTTP verbs.
Tabbed browsing and XSRFTabbed browsing actually makes XSRF more likely to succeed. The reasoning here is that all tabs share the same set of session cookies (session cookies are cookies that are deleted when the browser is closed), and users tend to be logged in to several sites at the same time. A malicious script in a tab, is thus more likely to succeed in performing malicious authenticated requests on behalf of the user.
Of course this is not a unique problem to tabbed browsing. When using the "File->Open new window" in IE6, the two windows would also share their session cookies. If opened from the start menu though, the new IE6 instance would be a completely separate process, and the two windows would not share their session cookies.
More informationUpdate 24.05.07: Ronald van den Heetkamp has a written an article about XSRF
here