Hello,**** ** **
*Background information:* We are trying to protect our RESTful APIs<http://en.wikipedia.org/wiki/Representational_state_transfer> from CSRF attack.**** The current Tomcat’s CSRF protection filter provides proper protection for web resources that are supposed to be accessed via some sort of navigation i.e. there’s an entry point which points to them (for example include links/post forms to them) . With REST APIs you do not have such entry points as the requests are done independently from each other. We are interested do you consider supporting CSRF protection for RESTful APIs?**** ** ** *Example attack:* Here is an example how to reproduce CSRF attack of RESTful APIs using the attached apps:**** 1. Check customers initial state: http://localhost:8080/restDemo/services/customers/ + login with tomcat/tomcat 2. **In the same browser open attacker’s app: http://localhost:8080/XSRFAttackerApp/ ** Behind the scenes request 2. takes advantage of your credentials stored in the browser and makes attacking POST request to a state changing operation http://localhost:8080/restDemo/services/customers/removeFirst on your behalf. After that the customer list is empty.**** ** ** The problem is that if we use the CSRF filter to protect this API /services/customers/removeFirst, this URL is then always served with *403 Forbidden* (due to the missing csrf token). In fact the REST API becomes unusable.**** ** ** *Research:* We’ve made some research on the topic and it seems that there is no absolutely secure and at the same time clear stateless solution. Since it is possible for an attacker to insert custom headers in the attacking requests, the validation over header presence is not secure enough.**** The only stable solution is again based on Synchronizer Token Pattern<https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet> but instead of encoded in URLs, the csrf token value can be transferred from and to the client through a custom csrf token header. The rest csrf token value needs to be stored in some sort of state on client and server side. In addition REST clients need to adopt this csrf token transfer mechanism.** ** *Proposal:* You can find on the link https://docs.google.com/open?id=0B-HUwAvkRIKJTVViWUFkNFl6alU , the CsrfPreventionFilter extended so that it is able to successfully protect state changing REST requests. They are validated based on the “X-CSRF-Token” header (the header name is configurable). * * *Here are some details about the new protection mechanism:* 1. How to recognize REST from non REST requests so that they can be validated separately - based on different tokens? - There is no clear way to recognize them, that’s why application developers should point all rest API URLs in the application through a new filter init parameter named *restApis*. 2. How the valid client gets to know the valid CSRF Token? - In order a REST client (e.g. adapted HTTP client) to obtain a valid CSRF token and use it for its REST requests it should make an initial non modifying request (GET, HEAD, OPTIONS) to the application. This request should contain ‘*X-CRF-Token: Fetch’ *header*. *On such request, the filter generates and stores a rest csrf token as a session attribute and returns it together with the jsessionid to the client. 3. The Client should send the pair j*sessionid* and * csrf token* header* *whenever it makes modifying REST requests to this application (POST, PUT, DELETE etc.). 4. How are invalid state changing requests handled? - They are responded with HTTP/1.1 403 Forbidden + ‘X-CSRF-Token: Required’ header. Below you can find example request response process flow. It is based on the example app - restDemo (also available on the link with the extended filter).**** To try it yourself: apply the patch, remove the commented CSRF protection configuration in restDemo’s web.xml and deploy. * 1.**Client Request 1:** *GET /restDemo/services/customers/ HTTP/1.1 X-CSRF-Token: Fetch Authorization: Basic dG9tY2F0OnRvbWNhdA== Host: localhost:8080 * * *Server Response1:* HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Cache-Control: private Expires: Thu, 01 Jan 1970 03:00:00 EET *Set-Cookie: JSESSIONID=4BA3D75B73B8C4591F1D915BA9C2B660; Path=/restDemo/; HttpOnly* *X-CSRF-Token: 5A44B387B75E54417F6C64FF3D485141* Content-Type: application/xml Content-Length: 170 Date: Fri, 21 Sep 2012 17:53:02 GMT * * *2. ****Client Request 2:* POST /restDemo/services/customers/removeFirst HTTP/1.1 *Cookie: JSESSIONID=4BA3D75B73B8C4591F1D915BA9C2B660* *X-CSRF-Token: 5A44B387B75E54417F6C64FF3D485141* Authorization: Basic dG9tY2F0OnRvbWNhdA== Host: localhost:8080 * * *Server Response2:* HTTP/1.1 200 OK Server: Apache-Coyote/1.1 *Set-Cookie: JSESSIONID=03D21FD4498B1446F12A3796441E2598; Path=/restDemo/; HttpOnly -> sessionid is rechanged after reauthentication (this is not related to our proposal but the client needs to track such session changes)* Content-Type: text/html Transfer-Encoding: chunked Date: Fri, 21 Sep 2012 17:53:47 GMT * * *3. ****Client Request 3:* POST /restDemo/services/customers/removeFirst HTTP/1.1 *Cookie: JSESSIONID=03D21FD4498B1446F12A3796441E2598* *X-CSRF-Token: 5A44B387B75E54417F6C64FF3D485141* Authorization: Basic dG9tY2F0OnRvbWNhdA== Host: localhost:8080 * * *Server Response3:* HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/html Transfer-Encoding: chunked Date: Fri, 21 Sep 2012 17:59:56 GMT * * *4. Client Requests 4 (negative case 1 ):* POST /restDemo/services/customers/removeFirst HTTP/1.1 Cookie: JSESSIONID=03D21FD4498B1446F12A3796441E2598 Authorization: Basic dG9tY2F0OnRvbWNhdA== Host: localhost:8080 * * *5. ****Client Requests 5 (negative case 2):* POST /restDemo/services/customers/removeFirst HTTP/1.1 Cookie: JSESSIONID=03D21FD4498B1446F12A3796441E2598 *X-CSRF-Token: fetch* Authorization: Basic dG9tY2F0OnRvbWNhdA== Host: localhost:8080 * * *6. ****Client Requests 6 (negative case 3):* POST /restDemo/services/customers/removeFirst HTTP/1.1 Cookie: JSESSIONID=03D21FD4498B1446F12A3796441E2598 *X-CSRF-Token: invalid* Authorization: Basic dG9tY2F0OnRvbWNhdA== Host: localhost:8080 Requests [4 – 6] are all responded with: * * *Server Response (negative cases 1-3)* *HTTP/1.1 403 Forbidden* Server: Apache-Coyote/1.1 *X-CSRF-Token: Required* Content-Type: text/html;charset=utf-8 Content-Length: 961 Date: Fri, 21 Sep 2012 18:03:16 GMT We are looking forward to your comments. Best Regards Violeta and Polina