View source | View content page | Page history | Printable version   

Projects:CSRF Token/Specs

Contents

Functional Requirements

Overview

Cross-Site Request Forgery (CSRF) is an attack where a malicious attacker makes a user’s browser to perform an unauthorized action on a trusted site for which the user is authenticated.

As the attacker has no way to receiver the command results, this attack is used to perform state-changing actions (i.e. changing a Product’s price) instead of simply fetching data.

Recommended approaches

OWASP recommends in their CSRF Prevention Cheat Sheet two complementary approaches to protect applications against CSRF attacks:

This OWASP document notes that although the security can be improved using a different token per request, it may also leads to usability issues.

Reference Implementations

CSRF Protection is a basic security feature that is implemented in most web application frameworks. The following are examples of how web applications/frameworks tackles this issue.

Tomcat

Starting from version 7, Tomcat introduces a Filter that protects all non-GET requests introducing a nonce (one-use token string) that is known only by the server and the authenticated user. This nonce is stored in the HttpSession and can hold up to a defined number of the last generated tokens. A new nonce is generated when a response is retrieved and appended to the URL as a Query string.

Joomla

Joomla uses CSRF Token both in GET and POST requests. GET requests appends the token as a Query string while POST requests introduces a hidden field with the token. In any case, this token is unique per Session and per user. In fact, it is generated as a md5 hash of the User id appended with the Session token.

Symfony

Symfony implements by default a CSRF token that is unique per Session. Simfony lets you define a different token for each Form to improve security. To define a CSRF token in a manual form:

<input type="hidden" name="token" value="{{ csrf_token('delete-item') }}" />

Then in the controller you can check the token is valid with the following:

if ($this->isCsrfTokenValid('delete-item', $submittedToken))

Spring

Spring Security implements a synchronizer token pattern storing the token in the HttpSession object. This token is included as a hidden field in forms and as a HTTP header (X-CSRF-TOKEN) for Ajax and JSON requests. This token is used in all HTTP verbs that may change state of the application (POST, PUT, PATCH, DELETE). For a detailed documentation of applications and caveats of using CSRF protection, check out Spring Security documentation.

Technical Requirements

The solution adopted for this project is to implement only the Synchronizer token pattern, as it provides a fairly good protection against the attack by itself while remaining transparent for the rest of the system. To implement this pattern, a number of steps should be taken:

Backoffice

CSRF Protection is only implemented on standard ERP windows for state changing operations (ie. POST for saving entries or PUT to edit).

Generate and store the token

The token should be generated when the session starts and remain the same until the user logs out. For this reason the token is generated using SequenceIdData.getUUID(), which uses the UUID generator but removing the dashes and converting the characters to upper-case. This generation is performed in LoginUtils.fillSessionArguments and the resulting token is stored in the user session.

Bulbgraph.png   Note that generating the token un LoginUtil implies that the token is renewed every time the session changes, i.e. when the user changes its role.

Make this token available in the client side

The token generated in the previous step will be retrieved to the client using the SessionDynamic request, and the token will be accesible in the JS generated code as OB.User.csrfToken.

Bulbgraph.png   As Unit Tests (i.e. BaseDataSourceTestDal tests) does not use the generated JS to make requests, they make a SessionDynamic request and extract the token from the response.

Add the token in all required requests

There are two places to add the token to cover all backoffice standard windows: the standard view datasource and the notes view to add/remove notes. The most straightforward approach to include a parameter in all required requests is by adding it as a new parameter in ob-standard-view-datasource and in ob-view-form-notes, but it has a drawback: these parameters will be included in the URL query string, making the token visible for POST/PUT/DELETE requests, which is not desiderable.

For this reason, the OBRestDataSource (which is the common ancestor for the standard view and the notes datasource) is extended to support a csrfToken parameter that will be included in the JSON payload in POST/PUT request and in the query string in DELETE request, because DELETE requests has no payload.

Verify the token in the server side

Token check can be performed in a centralized way in the DataSourceServlet class. It takes the token from the JSON payload for POST and PUT requests while it is extracted from the query string parameters in DELETE requests.

POS

In retail POS we followed a similar approach as backoffice, but with some implementation changes.

In this case, protection is applied to POST requests handled by MobileService that are not self-authenticated, that is, requests that rely on the session created by the login request to authenticate.

Generate and store the token

As MobileCoreLoginHandler extends from LoginHandler, token is still generated and saved in the Session. No changes needed in this step.

Make this token available in the client side

Token is available through the response of preRenderActions command of loginutils. This response is used by ob-terminal-model to store this value as OB.MobileApp.model.get('csrfToken').

Add the token in all required requests

All POST requests are processed using OB.DS.Process.prototype.exec, so by adding the CSRF token in the data, it will be included in all POST requests.

Verify the token in the server side

MobileService has a doGetOrPost method which is common for GET and POST requests. In case it receives a POST request, the CSRF token is checked and if token is invalid, it returns a response with HTTP Unauthorized code (401), which will show a dialog to the user prompting them to restart their session.

Retrieved from "http://wiki.openbravo.com/wiki/Projects:CSRF_Token/Specs"

This page has been accessed 1,444 times. This page was last modified on 19 September 2018, at 16:50. Content is available under Creative Commons Attribution-ShareAlike 2.5 Spain License.