Just when developers are starting to run in circles over Cross Site Scripting (XSS), the 'sleeping giant' awakes for yet another web-catastrophe. Cross-Site Request Forgery (CSRF) is an attack whereby the victim is tricked into loading information from or submitting information to a web application for which they are currently authenticated. The problem is that the web application has no means of verifying the integrity of the request.
How does the attack work?
There are numerous ways in which an end-user can be tricked into loading information from or submitting information to a web application. In order to execute an attack, we must first understand how to generate a malicious request for our victim to execute. Let us consider the following example: Alice wishes to transfer $100 to Bob using bank.com. The request generated by Alice will look similar to the following:
POST http://bank.com/transfer.do HTTP/1.1 ... ... ... Content-Length: 19; acct=BOB&amount=100
However, Maria notices that the same web application will execute the same transfer using URL parameters as follows:
GET http://bank.com/transfer.do?acct=BOB&amount=100 HTTP/1.1
Maria now decides to exploit this web application vulnerability using Alice as her victim. Maria first constructs the following URL which will transfer $100,000 from Alice's account to her account:
Now that her malicious request is generated, Maria must trick Alice into submitting the request. The most basic method is to send Alice an HTML email containing the following:
<a href="http://bank.com/transfer.do?acct=MARIA&amount=100000">View my Pictures!</a>
Assuming Alice is authenticated with the application when she clicks the link, the transfer of $100,000 to Maria's account will occur. However, Maria realizes that if Alice clicks the link, then Alice will notice that a transfer has occurred. Therefore, Maria decides to hide the attack in a zero-byte image:
<img src="http://bank.com/transfer.do?acct=MARIA&amount=100000" width="1" height="1" border="0">
If this image tag were included in the email, Alice would only see a little box indicating that the browser could not render the image. However, the browser will still submit the request to bank.com without any visual indication that the transfer has taken place.
Prevention measures that do NOT work
- Using a secret cookie
- Remember that all cookies, even the secret ones, will be submitted with every request. All authentication tokens will be submitted regardless of whether or not the end-user was tricked into submitting the request. Furthermore, session identifiers are simply used by the application container to associate the request with a specific session object. The session identifier does not verify that the end-user intended to submit the request.
- Only accepting POST requests
- Applications can be developed to only accept POST requests for the execution of business logic. The misconception is that since the attacker cannot construct a malicious link, a CSRF attack cannot be executed. Unfortunately, this logic is incorrect. Unintentional POST requests can still be generated using frames, scripts, etc..
//FIXME: provide example
Recommended Prevention Measure: Unique Request Tokens
The core issue with CSRF attacks is that form submission can be imitated with forged requests. The application must be able to differentiate between legal requests and forged requests. Since all headers, cookies, and credentials will be submitted with both legal and forged requests, the only method of truly verifying the integrity of the request is with a uniquely identifiable token in the form of an HTTP parameter. When a request is received, the application must verify the existence of the unique token as well as its value. The security of the approach is based on the fact that this unique token value is hard to guess. Therefore, it is imperative that this value is large and cryptographically secure.
A Java CSRF Guard
J2EE filters provide the ability to intercept, view, and modify both the request and associated response for the requesting client. Filters are inserted and executed by the J2EE container's deployment descriptor (web.xml) file. For example, if an HTTP request for a JSP page hits our Apache web server, the request is sent to Tomcat for processing. Before Tomcat executes the code inside of the JSP, the request must be passed along a chain of J2EE filters. The following snippet illustrates how to declare and map a filter to a particular URI-space in web.xml:
<filter> <filter-name>CSRFGuard</filter-name> <filter-class>org.owasp.csrf.CSRFGuard</filter-class> <init-param> <param-name>error-page</param-name> <param-value>error.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>CSRFGuard</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Implementing the CSRF Guard as a J2EE Filter gives us the ability to verify the integrity of the request before it ever hits our web application.
So how does it work?
- HTML Parsing and modification (limitations)
- Source code with description