Protecting Http Servlets against CSRF

Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious Web site, email, blog, instant message, or program causes a user’s Web browser to perform an unwanted action on a trusted site for which the user is currently authenticated. Any web request that can result in a state change is considered vulnerable to CSRF attacks. For example, HTTP POST requests typically result in a state change and are susceptible to CSRF attacks.

Niagara currently has a Servlet Filter that can be configured to route your servlets via the filter and verify if they are CSRF protected. This document will help you ensure your servlets are correctly configured and accessed to ensure CSRF protection.

Configuration

CsrfProtectedFilter is the Filter class that is defined in the web.XML file of the web module. In your web.xml file, configure the servlet(s) specifying the Http methods to be protected. See example below that protects the POST method of /rpc servlet requests.

Note that additional Http methods to be protected can be provided as comma (“,”) separated. Example, POST, PUT, DELETE

<!-- CSRF Protect NiagaraRpcServlet servlet -->
<filter>
  <filter-name>csrfProtectedNiagaraRpcFilter</filter-name>
  <filter-class>javax.baja.web.filters.CsrfProtectedFilter</filter-class>
  <init-param>
    <param-name>httpMethod</param-name>
    <param-value>POST</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>csrfProtectedNiagaraRpcFilter</filter-name>
  <url-pattern>/rpc</url-pattern>
</filter-mapping>

The above configuration now protects /rpc POST requests against CSRF. Just by making this change to your web.xml, you will ensure that all /rpc requests are rejected with a unauthorized exception if a valid token (explained below) is not passed with the request.

Passing the CSRF token

A CSRF token is generated per session and must be passed with every request that is intended to be protected from CSRF attacks.

There are 3 ways a CSRF token can be passed from a client,

As a query string

Example:
http://localhost/SampleServletGet?csrfToken=aToken

NOTE: How to get the token is discussed in a separate section below

As a form post parameter

The CSRF token is already embedded in all the profiles and will be automatically available for every form POST.

Explictly as a Http header

“x-niagara-csrfToken” is the Http header key that will carry the CSRF token.

//Sample jquery ajax request with csrf header
$.ajax(url, {
  dataType: "text",
  method: "PUT",
  data: someData,
  headers: {
    "x-niagara-csrfToken": "aToken"
  }
})

See Examples and API.

NOTE: For an AJAX POST/PUT kind of requests, it is strongly recommended to pass the csrftoken as a header and not part of the form post body which may lead to unexpected behavior. Passing via header also ensures the request stream is not consumed.

How to get the CSRF token in different Niagara profiles/views

Bajaux and Hx views have APIs to access the CSRF token.

//HxViews can get a token using this API
String csrfToken = SessionManager.getCurrentNiagaraSuperSession().getCsrfToken();
//HxViews can also get a token using the global "hx" Javascript API
var csrfToken = hx.getCsrfToken();
//Bajaux editors/widgets access a token via this API
define(["nmodule/js/rc/csrf/csrfUtil"], function(csrfUtil){
  'use strict';

  var csrfToken = csrfUtil.getCsrfToken();
});

CSRF Utility (JAVA)

There is a public utility class in the web module CsrfUtil.java that provides overloaded functions to verify an incoming CSRF token.

This utility will come in handy and may be used only for code that cannot use the CsrfProtectedFilter.

//Example usage
if(CsrfUtil.verifyCsrfToken(request /*HttpServletRequest*/)){//Do something}

Velocity and Mobile views

The CSRF token is also available in velocity and mobile profiles.

<!-- Access to CSRF token in a velocity template (.vm file)-->
$csrfToken //This parameter can be used anywhere in a template to get the CSRF token.

Mobile profile is internally generated via Velocity and the same parameter “$csrfToken” is available as a form field embedded in the profile.

Simply calling $(‘#csrfToken’) inside a mobile view will return the CSRF token.