@Provider
@Priority(value=400)
public class CsrfTokenFilter
extends java.lang.Object
implements javax.ws.rs.container.ContainerRequestFilter, javax.ws.rs.container.ContainerResponseFilter
To enable REST requests to work from the br
CLI and regular curl
without CSRF,
this CSRF protection only applies when a session is in effect.
Sessions are only established by some REST requests:
ServerApi.getUpExtended()
is a good choice (/v1/server/up/extended).
It can also be forced by using the CSRF_TOKEN_REQUIRED_HEADER
header on any REST request.
Browser-based UI clients should use one of the above methods early in operation.
The standard model is that the token is required for all write (ie non-GET) requests being made with a valid session cookie (ie the request is part of an ongoing session). In such cases, the client must send the X-Csrf-Token as a header. This prevents a third-party site from effecting a mutating cross-site request via the browser.
For transitional reasons, the default behaviour in the current implementation is to warn (not fail) if no token is supplied in the above case. This will likely be changed to enforce the standard model in a subsequent version, but it avoids breaking backwards compatibility for any existing session-based clients.
Clients can force different required behaviour (e.g. "fail") by including the
CSRF_TOKEN_REQUIRED_HEADER
with one of the values in CsrfTokenFilter.CsrfTokenRequiredForRequests
,
viz. to require the header on ALL requests, or on NONE, instead of just on WRITE requests (the default).
If such a mode is explicitly specified it is enforced (instead of just displaying the transitional warning),
so while transitioning to enforce CSRF this header should be supplied.
The Brooklyn UI does this.
This uses *two* names, Csrf-Token
and Xsrf-Token
.
The former seems the usual convention, but Angular apps use the latter.
This strategy should mean that Angular apps should get CSRF protection with no special configuration.
The cookies are sent by the client on every request, by virtue of being cookies,
although this is not necessary (and rather wasteful). A client may optimise by deleting the cookies
and caching the information in another form.
The cookie names do not have any salt/uid, so in dev on localhost you may get conflicts, e.g. between
multiple Brooklyn instances or other apps that use the same token names.
(In contrast the session ID token, usually JSESSIONID, has a BROOKLYN
Additional CSRF strategies might be worth considering, in addition to the one described above:
More info at: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet .
(These have not been implemented because the cookie pattern is sufficient, and one of the strongest.)
Modifier and Type | Class and Description |
---|---|
static class |
CsrfTokenFilter.CsrfTokenRequiredForRequests |
Modifier and Type | Field and Description |
---|---|
static java.lang.String |
CSRF_TOKEN_REQUIRED_ATTR |
static java.lang.String |
CSRF_TOKEN_REQUIRED_HEADER |
static java.lang.String |
CSRF_TOKEN_VALUE_ATTR |
static java.lang.String |
CSRF_TOKEN_VALUE_BASE_ANGULAR_NAME |
static java.lang.String |
CSRF_TOKEN_VALUE_COOKIE |
static java.lang.String |
CSRF_TOKEN_VALUE_COOKIE_ANGULAR_NAME |
static java.lang.String |
CSRF_TOKEN_VALUE_HEADER |
static java.lang.String |
CSRF_TOKEN_VALUE_HEADER_ANGULAR_NAME |
static CsrfTokenFilter.CsrfTokenRequiredForRequests |
DEFAULT_REQUIRED_FOR_REQUESTS |
Constructor and Description |
---|
CsrfTokenFilter() |
Modifier and Type | Method and Description |
---|---|
void |
filter(javax.ws.rs.container.ContainerRequestContext requestContext) |
void |
filter(javax.ws.rs.container.ContainerRequestContext requestContext,
javax.ws.rs.container.ContainerResponseContext responseContext) |
static java.lang.String |
HEADER_OF_COOKIE(java.lang.String cookieName) |
public static final java.lang.String CSRF_TOKEN_VALUE_COOKIE
public static final java.lang.String CSRF_TOKEN_VALUE_HEADER
public static final java.lang.String CSRF_TOKEN_VALUE_BASE_ANGULAR_NAME
public static final java.lang.String CSRF_TOKEN_VALUE_COOKIE_ANGULAR_NAME
public static final java.lang.String CSRF_TOKEN_VALUE_HEADER_ANGULAR_NAME
public static final java.lang.String CSRF_TOKEN_VALUE_ATTR
public static final java.lang.String CSRF_TOKEN_REQUIRED_HEADER
public static final java.lang.String CSRF_TOKEN_REQUIRED_ATTR
public static CsrfTokenFilter.CsrfTokenRequiredForRequests DEFAULT_REQUIRED_FOR_REQUESTS
public static java.lang.String HEADER_OF_COOKIE(java.lang.String cookieName)
public void filter(javax.ws.rs.container.ContainerRequestContext requestContext) throws java.io.IOException
filter
in interface javax.ws.rs.container.ContainerRequestFilter
java.io.IOException
public void filter(javax.ws.rs.container.ContainerRequestContext requestContext, javax.ws.rs.container.ContainerResponseContext responseContext) throws java.io.IOException
filter
in interface javax.ws.rs.container.ContainerResponseFilter
java.io.IOException