wiki:proposals/CSRFTokens

Proposal title

Date 2013/02/24
Contact(s) Jose García, Heikki Doeleman
Last edited
Status in progress
Assigned to release To be determined
Resources https://github.com/josegar74/core-geonetwork/tree/csrf
Ticket #

Overview

Improve the security in GeoNetwork, adding support to CSRF tokens to prevent Cross-Site Request Forgery. Also fixes have been done in user request parameters accepted in main page to prevent XSS attacks.

Proposal Type

  • Type: Core Change
  • App: GeoNetwork
  • Module: Jeeves, Services
  • Documents:
  • Email discussions:
  • Other wiki discussions:

Voting History

  • Vote proposed by X on Y, result was +/-n (m non-voting members).

Motivations

Improve the security in GeoNetwork to prevent CSRF (Cross-site request forgery) attacks. This type of attacks force an end user to execute unwanted actions on a web application in which he/she is currently authenticated. See additional information in https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)

Additionally, improvements in main page have been done to prevent XSS attacks in user requests parameters.

Proposal

An effective way to prevent CSRF attacks it is to generate a random string (CSRF token) that is included in application forms. When the form is submitted, the CSRF token is send along the other form data, the server validates it before. approving the request for processing.

This way, prevents a malicious website from post a request even if have access to a valid session in a browser.

To implement this mechanism in GeoNetwork:

1) A new base service class for services that require CSRF (Cross Site Request Forgery) tokens: BaseSecureService

This class validates the CSRF token before processing the service:

  • If it's not valid and exception ServiceNotAllowedEx is thrown.
  • If it's valid, the service processing continues.
package jeeves.services;

public abstract class BaseSecureService implements Service {
    public final Element exec(Element params, ServiceContext context) throws Exception {
        if (!CSRFUtil.isValidToken(params, context)) {
            throw new ServiceNotAllowedEx("Service not allowed. CSRF Token is not valid");
        }

        return doExec(params, context);
    }

    /** Services that require CSRF tokens must implement doExec instead of exec **/
    protected abstract Element doExec(Element params, ServiceContext context) throws Exception;
}

Services that require CSRF tokens must extend this class and implement the logic in doExec method instead of exec method.

package org.fao.geonet.services.user;

public class Update extends BaseSecureService
{
        public Element doExec(Element params, ServiceContext context) throws Exception
	{
                // Service logic  
        }
}

Code: https://github.com/josegar74/core-geonetwork/blob/csrf/jeeves/src/main/java/jeeves/services/BaseSecureService.java

Example service requiring CSRF token: https://github.com/josegar74/core-geonetwork/blob/csrf/web/src/main/java/org/fao/geonet/services/user/Update.java

2) A new service to create/retrieve a CSRF token: secure.token. This service is used to provide the secure token in services that create forms (see next point) and can be used from scripts that use actual GeoNetwork services that have been changed to require CSRF tokens. For example, a script that call metadata.category to update the categories of metadata, will require to call first secure.token to get the token and use it in metadata.category calls.

CSRF tokens are created using SecureRandom java class.

Code: https://github.com/josegar74/core-geonetwork/blob/csrf/jeeves/src/main/java/jeeves/services/GetSecureToken.java, https://github.com/josegar74/core-geonetwork/blob/csrf/jeeves/src/main/java/jeeves/utils/CSRFUtil.java

3) Services that create forms to submit data to services that require CSRF tokens validation require to add this token in the form to submit. This requires 2 changes:

  • Update service definition to provide the CSRF token:
<service name="user.edit">
	<class name=".services.user.Get" />

	<output sheet="user-update.xsl">
		<call name="groups" class=".guiservices.groups.GetMine" />
		<call name="groupsAndProfiles" class=".guiservices.groups.GetMineWithProfiles" />
		<call name="profiles" class="jeeves.guiservices.profiles.Get" />
		
		<call name="_tk" class="jeeves.services.GetSecureToken" />
	</output>
</service>
  • Add the token value as a hidden field in the form:
<form name="userupdateform" accept-charset="UTF-8" action="{/root/gui/locService}/user.update?operation=editinfo" method="post">
        <input type="hidden" name="_tk" value="{/root/gui/_tk}"/>

Also as part of this work security improvements in main page user request parameters have been done to prevent XSS attacks: https://github.com/josegar74/core-geonetwork/commit/50f722f12c36e403ffa80724004e937db0ef2821

Useful resources:

Backwards Compatibility Issues

User scripts using GeoNetwork services to update data will require to be updated to use secure.token to retrieve the CSRF token and use it in the services. See Proposal description (point 2) for more details. These changes don't affect interfaces like CSW.

UI WIdgets requires to be changed to use the CSRF token.

New libraries added

Risks

Participants

  • Jose García
  • Heikki Doeleman
Last modified 11 years ago Last modified on Feb 24, 2013, 11:45:19 AM
Note: See TracWiki for help on using the wiki.