Availability | Confluence 3.0 or later |
This page demonstrates how to protect your app’s Struts actions and servlets from cross-site request forgery (XSRF) attacks (also known as CSRF attacks).
An XSRF token is a unique, secret, unpredictable value that is generated by the server-side application and transmitted to the client in such a way that it’s included in a subsequent HTTP request made by the client.
XSRF protection is an opt-out feature (opt-in prior to Confluence 9.0) for Struts Actions, and opt-in for servlets.
Actions, by default, will only accept POST requests, EXCEPT for Actions which map to a method named doDefault
which
will accept GET or POST. We strongly recommend restricting your Actions to accept only its required request methods.
Ordinarily, any request which mutates application state (e.g. handling a form submission) should NOT accept GET (or
HEAD, OPTIONS, TRACE) requests. It also follows that any request which mutates application state should require an
XSRF token.
The accepted request methods for an Action can be configured in 2 ways. In both cases you must ensure your Action
package defines or inherits the validatingStack
interceptor stack (<interceptor-ref name="validatingStack"/>
).
Locate the Java method which an Action maps to and add the following annotation, specifying the desired request methods:
1 2@com.atlassian.xwork.PermittedMethods({HttpMethod.GET, HttpMethod.TRACE})
Locate the Action definition in atlassian-plugins.xml
and add the following child element, specifying the desired
request methods:
1 2<param name="permittedMethods">GET,TRACE</param>
All requests made to Struts Actions which are not GET (or HEAD, OPTIONS, TRACE) requests will require a token unless explicitly opted out. All GET (or HEAD, OPTIONS, TRACE) requests will not require a token unless explicitly opted in. Ideally, your app will not have any Actions that accept these safe request methods and mutate application state, and so explicitly opting in should be rarely required.
A Struts action can be configured to require or not require a token in 2 ways.
Locate the Java method which an Action maps to and add the following annotations.
To opt-out (for non-GET requests):
1 2@com.atlassian.annotations.security.XsrfProtectionExcluded
To opt-in (for GET requests):
1 2@com.atlassian.xwork.RequireSecurityToken(true)
Locate the Action definition in atlassian-plugins.xml
and add the following child element.
To opt-out (for non-GET requests):
1 2<param name="RequireSecurityToken">false</param>
To opt-in (for GET requests):
1 2<param name="RequireSecurityToken">true</param>
Here are examples of a Struts Action which accepts both GET
and POST
requests and does not require a token:
1 2@XsrfProtectionExcluded @PermittedMethods({HttpMethod.GET, HttpMethod.POST}) public String execute() throws Exception { return SUCCESS; }
1 2<action name="index" class="com.atlassian.confluence.core.ConfluenceActionSupport"> <param name="RequireSecurityToken">false</param> <param name="permittedMethods">GET,POST</param> <result name="success" type="dispatcher">/admin/console.action</result> </action>
To enable servlet XSRF protection add an init parameter in atlassian-plugin.xml
under the servlet tag:
1 2<init-param> <param-name>RequireSecurityToken</param-name> <param-value>true</param-value> </init-param>
Here’s an example atlassian-plugin.xml
file containing a single servlet with XSRF protection enabled:
1 2<atlassian-plugin name="Hello World Servlet" key="example.plugin.helloworld" plugins-version="2"> <plugin-info> <description>A basic Servlet module test - says "Hello World!</description> <vendor name="Atlassian Software Systems" url="http://www.atlassian.com"/> <version>1.0</version> </plugin-info> <servlet name="Hello World Servlet" key="helloWorld" class="com.example.myplugins.helloworld.HelloWorldServlet"> <description>Says Hello World, Australia or your name.</description> <url-pattern>/helloworld</url-pattern> <init-param> <param-name>RequireSecurityToken</param-name> <param-value>true</param-value> </init-param> </servlet> </atlassian-plugin>
The way you provide the token depends on how the request is made.
In order for either the Struts action or servlet XSRF protection to work, apps must ensure that "safe" HTTP methods are idempotent. This means that requests with the HTTP method GET
, HEAD
, OPTIONS
, and TRACE
should not change the state of the application.
The Velocity macro #form_xsrfToken()
will insert the following into your form:
1 2<input type="hidden" name="atl_token" value="[the user's token]">
The Atlassian Javascript Library (AJS) contains a method that will add the security token to an AJAX callback. To make this method available, place the following call in your Velocity template:
1 2#requireResource("confluence.web.resources:safe-ajax")
This library provides wrappers around JQuery AJAX functions that will include the form token in the AJAX submission. If you’re not using the JQuery AJAX functions, you should first update your code to use them directly, then use the safe version. The following functions are provided:
1 2AJS.safe.ajax() AJS.safe.post()
To provide the token in AJAX calls directly:
1 2AJS.Meta.get("atl-token") Meta.get("atl-token")
To get the current user's token, make the following call:
1 2new com.atlassian.xwork.SimpleXsrfTokenGenerator().generateToken(httpServletRequest)
For the best long-term compatibility, you should retrieve the name of the form parameter to set from the token generator rather than using the literal string "atl_token". For example:
1 2HttpServletRequest req = ServletActionContext.getRequest(); if (req != null) { XsrfTokenGenerator tokenGenerator = new SimpleXsrfTokenGenerator(); myWebRequest.addParameter(tokenGenerator.getXsrfTokenName(), tokenGenerator.generateToken(req)) // or: myRequestUrl.append("&" + tokenGenerator.getXsrfTokenName() + "=" + tokenGenerator.generateToken(req)); } else { // We are not in a web context. Handle this error cleanly. }
Scripts used to access Confluence remotely may have trouble acquiring or returning a security token or maintaining an HTTP session with the server. To opt-out of token checking, include the following HTTP header in the request:
1 2X-Atlassian-Token: no-check
Rate this page: