org.apache.wicket.protocol.http
Class CsrfPreventionRequestCycleListener

java.lang.Object
  extended by org.apache.wicket.request.cycle.AbstractRequestCycleListener
      extended by org.apache.wicket.protocol.http.CsrfPreventionRequestCycleListener
All Implemented Interfaces:
IRequestCycleListener

public class CsrfPreventionRequestCycleListener
extends AbstractRequestCycleListener
implements IRequestCycleListener

Prevents CSRF attacks on Wicket components by checking the Origin and Referer HTTP headers for cross domain requests. By default only checks requests that try to perform an action on a component, such as a form submit, or link click.

Installation

You can enable this CSRF prevention filter by adding it to the request cycle listeners in your application's init method:

 @Override
 protected void init()
 {
        // ...
        getRequestCycleListeners().add(new CsrfPreventionRequestCycleListener());
        // ...
 }
 

Configuration

When the Origin or Referer HTTP header is present but doesn't match the requested URL this listener will by default throw a HTTP error ( 400 BAD REQUEST) and abort the request. You can configure this specific action.

A missing Origin and Referer HTTP header is handled as if it were a bad request and rejected. You can configure the specific action to a different value, suppressing or allowing the request when the HTTP headers are missing.

When the Origin HTTP header is present and has the value null it is considered to be from a "privacy-sensitive" context and will trigger the no origin action. You can customize what happens in those actions by overriding the respective onXXXX methods.

When you want to accept certain cross domain request from a range of hosts, you can whitelist those domains.

You can enable or disable this listener by overriding isEnabled().

You can customize whether a particular page should be checked for CSRF requests. For example you can skip checking pages that have a @NoCsrfCheck annotation, or only those pages that extend your base secure page class. For example:

 @Override
 protected boolean isChecked(IRequestablePage requestedPage)
 {
        return requestedPage.getPage() instanceof SecurePage;
 }
 

You can also tweak the request handlers that are checked. The CSRF prevention request cycle listener checks only action handlers, not render handlers. Override isChecked(IRequestHandler) to customize this behavior.

You can customize the default actions that are performed by overriding the event handlers for them:


Nested Class Summary
static class CsrfPreventionRequestCycleListener.CsrfAction
          The action to perform when a missing or conflicting source URI is detected.
 
Constructor Summary
CsrfPreventionRequestCycleListener()
           
 
Method Summary
protected  void abortHandler(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Handles the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to ABORT.
 CsrfPreventionRequestCycleListener addAcceptedOrigin(String acceptedOrigin)
          Adds an origin (host name/domain name) to the white list.
protected  void allowHandler(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Handles the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to ALLOW.
protected  void checkRequest(javax.servlet.http.HttpServletRequest request, String sourceUri, IRequestablePage page)
          Performs the check of the Origin or Referer header that is targeted at the page.
protected  String getSourceUri(javax.servlet.http.HttpServletRequest containerRequest)
          Resolves the source URI from the request headers (Origin or Referer).
protected  String getTargetUriFromRequest(javax.servlet.http.HttpServletRequest request)
          Creates a RFC-6454 comparable URI from the request requested resource.
protected  boolean isChecked(IRequestablePage targetedPage)
          Override to limit whether the request to the specific page should be checked for a possible CSRF attack.
protected  boolean isChecked(IRequestHandler handler)
          Override to change the request handler types that are checked.
protected  boolean isEnabled()
          Dynamic override for enabling/disabling the CSRF detection.
protected  boolean isLocalOrigin(javax.servlet.http.HttpServletRequest containerRequest, String originHeader)
          Checks whether the Origin HTTP header of the request matches where the request came from.
protected  boolean isWhitelistedHost(String sourceUri)
          Checks whether the domain part of the sourceUri (Origin or Referer header) is whitelisted.
protected  void matchingOrigin(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Handles the case where an origin was checked and matched the request origin.
protected  String normalizeUri(String uri)
          Creates a RFC-6454 comparable URI from the uri string.
protected  void onAborted(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Override this method to customize the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to ABORTED.
protected  void onAllowed(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Override this method to customize the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to ALLOW.
 void onBeginRequest(RequestCycle cycle)
          Called when the request cycle object is beginning its response
protected  void onMatchingOrigin(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Called when the origin HTTP header matched the request.
 void onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler)
          Called when an IRequestHandler is resolved and will be executed.
protected  void onSuppressed(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Override this method to customize the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to SUPPRESSED.
protected  void onWhitelisted(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Called when the origin was available in the whitelist.
 CsrfPreventionRequestCycleListener setConflictingOriginAction(CsrfPreventionRequestCycleListener.CsrfAction action)
          Sets the action when a conflicting Origin header is detected.
 CsrfPreventionRequestCycleListener setErrorCode(int errorCode)
          Modifies the HTTP error code in the exception when a conflicting Origin header is detected.
 CsrfPreventionRequestCycleListener setErrorMessage(String errorMessage)
          Modifies the HTTP message in the exception when a conflicting Origin header is detected.
 CsrfPreventionRequestCycleListener setNoOriginAction(CsrfPreventionRequestCycleListener.CsrfAction action)
          Sets the action when no Origin header is present in the request.
protected  void suppressHandler(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Handles the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to SUPPRESS.
protected  IRequestHandler unwrap(IRequestHandler handler)
          Unwraps the handler if it is a IRequestHandlerDelegate down to the deepest nested handler.
protected  void whitelistedHandler(javax.servlet.http.HttpServletRequest request, String origin, IRequestablePage page)
          Handles the case where an origin is in the whitelist.
 
Methods inherited from class org.apache.wicket.request.cycle.AbstractRequestCycleListener
onDetach, onEndRequest, onException, onExceptionRequestHandlerResolved, onRequestHandlerExecuted, onRequestHandlerScheduled, onUrlMapped
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface org.apache.wicket.request.cycle.IRequestCycleListener
onDetach, onEndRequest, onException, onExceptionRequestHandlerResolved, onRequestHandlerExecuted, onRequestHandlerScheduled, onUrlMapped
 

Constructor Detail

CsrfPreventionRequestCycleListener

public CsrfPreventionRequestCycleListener()
Method Detail

setNoOriginAction

public CsrfPreventionRequestCycleListener setNoOriginAction(CsrfPreventionRequestCycleListener.CsrfAction action)
Sets the action when no Origin header is present in the request. Default ALLOW.

Parameters:
action - the alternate action
Returns:
this (for chaining)

setConflictingOriginAction

public CsrfPreventionRequestCycleListener setConflictingOriginAction(CsrfPreventionRequestCycleListener.CsrfAction action)
Sets the action when a conflicting Origin header is detected. Default is ERROR.

Parameters:
action - the alternate action
Returns:
this

setErrorCode

public CsrfPreventionRequestCycleListener setErrorCode(int errorCode)
Modifies the HTTP error code in the exception when a conflicting Origin header is detected.

Parameters:
errorCode - the alternate HTTP error code, default 400 BAD REQUEST
Returns:
this

setErrorMessage

public CsrfPreventionRequestCycleListener setErrorMessage(String errorMessage)
Modifies the HTTP message in the exception when a conflicting Origin header is detected.

Parameters:
errorMessage - the alternate message
Returns:
this

addAcceptedOrigin

public CsrfPreventionRequestCycleListener addAcceptedOrigin(String acceptedOrigin)
Adds an origin (host name/domain name) to the white list. An origin is in the form of <domainname>.<TLD>, and can contain a subdomain. Every Origin header that matches a domain from the whitelist is accepted and not checked any further for CSRF issues. E.g. when example.com is in the white list, this allows requests from (i.e. with an Origin: header containing) example.com and blabla.example.com but rejects requests from blablaexample.com and example2.com.

Parameters:
acceptedOrigin - the acceptable origin
Returns:
this

onBeginRequest

public void onBeginRequest(RequestCycle cycle)
Description copied from interface: IRequestCycleListener
Called when the request cycle object is beginning its response

Specified by:
onBeginRequest in interface IRequestCycleListener
Overrides:
onBeginRequest in class AbstractRequestCycleListener

isEnabled

protected boolean isEnabled()
Dynamic override for enabling/disabling the CSRF detection. Might be handy for specific tenants in a multi-tenant application. When false, the CSRF detection is not performed for the running request. Default true

Returns:
true when the CSRF checks need to be performed.

isChecked

protected boolean isChecked(IRequestablePage targetedPage)
Override to limit whether the request to the specific page should be checked for a possible CSRF attack.

Parameters:
targetedPage - the page that is the target for the action
Returns:
true when the request to the page should be checked for CSRF issues.

isChecked

protected boolean isChecked(IRequestHandler handler)
Override to change the request handler types that are checked. Currently only action handlers (form submits, link clicks, AJAX events) are checked for a matching Origin HTTP header.

Parameters:
handler - the handler that is currently processing
Returns:
true when the Origin HTTP header should be checked for this handler

unwrap

protected final IRequestHandler unwrap(IRequestHandler handler)
Unwraps the handler if it is a IRequestHandlerDelegate down to the deepest nested handler.

Parameters:
handler - The handler to unwrap
Returns:
the deepest handler that does not implement IRequestHandlerDelegate

onRequestHandlerResolved

public void onRequestHandlerResolved(RequestCycle cycle,
                                     IRequestHandler handler)
Description copied from interface: IRequestCycleListener
Called when an IRequestHandler is resolved and will be executed.

Specified by:
onRequestHandlerResolved in interface IRequestCycleListener
Overrides:
onRequestHandlerResolved in class AbstractRequestCycleListener

getSourceUri

protected String getSourceUri(javax.servlet.http.HttpServletRequest containerRequest)
Resolves the source URI from the request headers (Origin or Referer).

Parameters:
containerRequest - the current container request
Returns:
the normalized source URI.

checkRequest

protected void checkRequest(javax.servlet.http.HttpServletRequest request,
                            String sourceUri,
                            IRequestablePage page)
Performs the check of the Origin or Referer header that is targeted at the page.

Parameters:
request - the current container request
sourceUri - the source URI
page - the page that is the target of the request

isWhitelistedHost

protected final boolean isWhitelistedHost(String sourceUri)
Checks whether the domain part of the sourceUri (Origin or Referer header) is whitelisted.

Parameters:
sourceUri - the contents of the Origin or Referer HTTP header
Returns:
true when the source domain was whitelisted

isLocalOrigin

protected boolean isLocalOrigin(javax.servlet.http.HttpServletRequest containerRequest,
                                String originHeader)
Checks whether the Origin HTTP header of the request matches where the request came from.

Parameters:
containerRequest - the current container request
originHeader - the contents of the Origin HTTP header
Returns:
true when the origin of the request matches the Origin HTTP header

normalizeUri

protected final String normalizeUri(String uri)
Creates a RFC-6454 comparable URI from the uri string.

Parameters:
uri - the contents of the Origin or Referer HTTP header
Returns:
only the scheme://host[:port] part, or null when the URI string is not compliant

getTargetUriFromRequest

protected final String getTargetUriFromRequest(javax.servlet.http.HttpServletRequest request)
Creates a RFC-6454 comparable URI from the request requested resource.

Parameters:
request - the incoming request
Returns:
only the scheme://host[:port] part, or null when the origin string is not compliant

whitelistedHandler

protected final void whitelistedHandler(javax.servlet.http.HttpServletRequest request,
                                        String origin,
                                        IRequestablePage page)
Handles the case where an origin is in the whitelist. Default action is to allow the whitelisted origin.

Parameters:
request - the request
origin - the contents of the Origin HTTP header
page - the page that is targeted with this request

onWhitelisted

protected void onWhitelisted(javax.servlet.http.HttpServletRequest request,
                             String origin,
                             IRequestablePage page)
Called when the origin was available in the whitelist. Override this method to implement your own custom action.

Parameters:
request - the request
origin - the contents of the Origin HTTP header
page - the page that is targeted with this request

matchingOrigin

protected final void matchingOrigin(javax.servlet.http.HttpServletRequest request,
                                    String origin,
                                    IRequestablePage page)
Handles the case where an origin was checked and matched the request origin. Default action is to allow the whitelisted origin.

Parameters:
request - the request
origin - the contents of the Origin HTTP header
page - the page that is targeted with this request

onMatchingOrigin

protected void onMatchingOrigin(javax.servlet.http.HttpServletRequest request,
                                String origin,
                                IRequestablePage page)
Called when the origin HTTP header matched the request. Override this method to implement your own custom action.

Parameters:
request - the request
origin - the contents of the Origin HTTP header
page - the page that is targeted with this request

allowHandler

protected final void allowHandler(javax.servlet.http.HttpServletRequest request,
                                  String origin,
                                  IRequestablePage page)
Handles the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to ALLOW.

Parameters:
request - the request
origin - the contents of the Origin HTTP header, may be null or empty
page - the page that is targeted with this request

onAllowed

protected void onAllowed(javax.servlet.http.HttpServletRequest request,
                         String origin,
                         IRequestablePage page)
Override this method to customize the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to ALLOW.

Parameters:
request - the request
origin - the contents of the Origin HTTP header, may be null or empty
page - the page that is targeted with this request

suppressHandler

protected final void suppressHandler(javax.servlet.http.HttpServletRequest request,
                                     String origin,
                                     IRequestablePage page)
Handles the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to SUPPRESS.

Parameters:
request - the request
origin - the contents of the Origin HTTP header, may be null or empty
page - the page that is targeted with this request

onSuppressed

protected void onSuppressed(javax.servlet.http.HttpServletRequest request,
                            String origin,
                            IRequestablePage page)
Override this method to customize the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to SUPPRESSED.

Parameters:
request - the request
origin - the contents of the Origin HTTP header, may be null or empty
page - the page that is targeted with this request

abortHandler

protected final void abortHandler(javax.servlet.http.HttpServletRequest request,
                                  String origin,
                                  IRequestablePage page)
Handles the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to ABORT.

Parameters:
request - the request
origin - the contents of the Origin HTTP header, may be null or empty
page - the page that is targeted with this request

onAborted

protected void onAborted(javax.servlet.http.HttpServletRequest request,
                         String origin,
                         IRequestablePage page)
Override this method to customize the case where an Origin HTTP header was not present or did not match the request origin, and the corresponding action (noOriginAction or conflictingOriginAction) is set to ABORTED.

Parameters:
request - the request
origin - the contents of the Origin HTTP header, may be null or empty
page - the page that is targeted with this request


Copyright © 2006–2019 Apache Software Foundation. All rights reserved.