Class CsrfPreventionRequestCycleListener
- java.lang.Object
-
- org.apache.wicket.protocol.http.CsrfPreventionRequestCycleListener
-
- All Implemented Interfaces:
IRequestCycleListener
public class CsrfPreventionRequestCycleListener extends java.lang.Object implements IRequestCycleListener
Prevents CSRF attacks on Wicket components by checking theOriginandRefererHTTP 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
OriginorRefererHTTP 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 canconfigurethis specific action.A missing
OriginandRefererHTTP header is handled as if it were a bad request and rejected. You canconfigure the specific actionto a different value, suppressing or allowing the request when the HTTP headers are missing.When the
OriginHTTP header is present and has the valuenullit 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 respectiveonXXXXmethods.When you want to accept certain cross domain request from a range of hosts, you can
whitelist those domains.You can
enable or disablethis listener by overridingisEnabled().You can
customizewhether a particular page should be checked for CSRF requests. For example you can skip checking pages that have a@NoCsrfCheckannotation, or only those pages that extend your base secure page class. For example:@Override protected boolean isChecked(IRequestablePage requestedPage) { return requestedPage 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:
onWhitelisted(HttpServletRequest, String, IRequestablePage)when an origin was whitelistedonMatchingOrigin(HttpServletRequest, String, IRequestablePage)when an origin was matchingonAborted(HttpServletRequest, String, IRequestablePage)when an origin was in conflict and the request should be abortedonAllowed(HttpServletRequest, String, IRequestablePage)when an origin was in conflict and the request should be allowedonSuppressed(HttpServletRequest, String, IRequestablePage)when an origin was in conflict and the request should be suppressed
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static classCsrfPreventionRequestCycleListener.CsrfActionThe action to perform when a missing or conflicting source URI is detected.
-
Constructor Summary
Constructors Constructor Description CsrfPreventionRequestCycleListener()
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description protected voidabortHandler(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toABORT.CsrfPreventionRequestCycleListeneraddAcceptedOrigin(java.lang.String acceptedOrigin)Adds an origin (host name/domain name) to the white list.protected voidallowHandler(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toALLOW.protected voidcheckRequest(javax.servlet.http.HttpServletRequest request, java.lang.String sourceUri, IRequestablePage page)Performs the check of theOriginorRefererheader that is targeted at thepage.protected java.lang.StringgetSourceUri(javax.servlet.http.HttpServletRequest containerRequest)Resolves the source URI from the request headers (OriginorReferer).protected java.lang.StringgetTargetUriFromRequest(javax.servlet.http.HttpServletRequest request)Creates a RFC-6454 comparable URI from therequestrequested resource.protected booleanisChecked(IRequestablePage targetedPage)Override to limit whether the request to the specific page should be checked for a possible CSRF attack.protected booleanisChecked(org.apache.wicket.request.IRequestHandler handler)Override to change the request handler types that are checked.protected booleanisEnabled()Dynamic override for enabling/disabling the CSRF detection.protected booleanisLocalOrigin(javax.servlet.http.HttpServletRequest containerRequest, java.lang.String originHeader)Checks whether theOriginHTTP header of the request matches where the request came from.protected booleanisWhitelistedHost(java.lang.String sourceUri)Checks whether the domain part of thesourceUri(OriginorRefererheader) is whitelisted.protected voidmatchingOrigin(javax.servlet.http.HttpServletRequest request, java.lang.String origin, IRequestablePage page)Handles the case where an origin was checked and matched the request origin.protected java.lang.StringnormalizeUri(java.lang.String uri)Creates a RFC-6454 comparable URI from theuristring.protected voidonAborted(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toABORTED.protected voidonAllowed(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toALLOW.voidonBeginRequest(RequestCycle cycle)Called when the request cycle object is beginning its responseprotected voidonMatchingOrigin(javax.servlet.http.HttpServletRequest request, java.lang.String origin, IRequestablePage page)Called when the origin HTTP header matched the request.voidonRequestHandlerResolved(RequestCycle cycle, org.apache.wicket.request.IRequestHandler handler)Called when anIRequestHandleris resolved and will be executed.protected voidonSuppressed(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toSUPPRESSED.protected voidonWhitelisted(javax.servlet.http.HttpServletRequest request, java.lang.String origin, IRequestablePage page)Called when the origin was available in the whitelist.CsrfPreventionRequestCycleListenersetConflictingOriginAction(CsrfPreventionRequestCycleListener.CsrfAction action)Sets the action when a conflicting Origin header is detected.CsrfPreventionRequestCycleListenersetErrorCode(int errorCode)Modifies the HTTP error code in the exception when a conflicting Origin header is detected.CsrfPreventionRequestCycleListenersetErrorMessage(java.lang.String errorMessage)Modifies the HTTP message in the exception when a conflicting Origin header is detected.CsrfPreventionRequestCycleListenersetNoOriginAction(CsrfPreventionRequestCycleListener.CsrfAction action)Sets the action when no Origin header is present in the request.protected voidsuppressHandler(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toSUPPRESS.protected org.apache.wicket.request.IRequestHandlerunwrap(org.apache.wicket.request.IRequestHandler handler)Unwraps the handler if it is aIRequestHandlerDelegatedown to the deepest nested handler.protected voidwhitelistedHandler(javax.servlet.http.HttpServletRequest request, java.lang.String origin, IRequestablePage page)Handles the case where an origin is in the whitelist.-
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
-
-
-
-
Method Detail
-
setNoOriginAction
public CsrfPreventionRequestCycleListener setNoOriginAction(CsrfPreventionRequestCycleListener.CsrfAction action)
Sets the action when no Origin header is present in the request. DefaultALLOW.- 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 isERROR.- 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, default400 BAD REQUEST- Returns:
- this
-
setErrorMessage
public CsrfPreventionRequestCycleListener setErrorMessage(java.lang.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(java.lang.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. whenexample.comis in the white list, this allows requests from (i.e. with anOrigin:header containing)example.comandblabla.example.combut rejects requests fromblablaexample.comandexample2.com.- Parameters:
acceptedOrigin- the acceptable origin- Returns:
- this
-
onBeginRequest
public void onBeginRequest(RequestCycle cycle)
Description copied from interface:IRequestCycleListenerCalled when the request cycle object is beginning its response- Specified by:
onBeginRequestin interfaceIRequestCycleListener
-
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. Defaulttrue- Returns:
truewhen 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:
truewhen the request to the page should be checked for CSRF issues.
-
isChecked
protected boolean isChecked(org.apache.wicket.request.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 org.apache.wicket.request.IRequestHandler unwrap(org.apache.wicket.request.IRequestHandler handler)
Unwraps the handler if it is aIRequestHandlerDelegatedown 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, org.apache.wicket.request.IRequestHandler handler)
Description copied from interface:IRequestCycleListenerCalled when anIRequestHandleris resolved and will be executed.- Specified by:
onRequestHandlerResolvedin interfaceIRequestCycleListener
-
getSourceUri
protected java.lang.String getSourceUri(javax.servlet.http.HttpServletRequest containerRequest)
Resolves the source URI from the request headers (OriginorReferer).- Parameters:
containerRequest- the current container request- Returns:
- the normalized source URI.
-
checkRequest
protected void checkRequest(javax.servlet.http.HttpServletRequest request, java.lang.String sourceUri, IRequestablePage page)Performs the check of theOriginorRefererheader that is targeted at thepage.- Parameters:
request- the current container requestsourceUri- the source URIpage- the page that is the target of the request
-
isWhitelistedHost
protected boolean isWhitelistedHost(java.lang.String sourceUri)
Checks whether the domain part of thesourceUri(OriginorRefererheader) is whitelisted.- Parameters:
sourceUri- the contents of theOriginorRefererHTTP header- Returns:
truewhen the source domain was whitelisted
-
isLocalOrigin
protected boolean isLocalOrigin(javax.servlet.http.HttpServletRequest containerRequest, java.lang.String originHeader)Checks whether theOriginHTTP header of the request matches where the request came from.- Parameters:
containerRequest- the current container requestoriginHeader- the contents of theOriginHTTP header- Returns:
truewhen the origin of the request matches theOriginHTTP header
-
normalizeUri
protected final java.lang.String normalizeUri(java.lang.String uri)
Creates a RFC-6454 comparable URI from theuristring.- Parameters:
uri- the contents of the Origin or Referer HTTP header- Returns:
- only the scheme://host[:port] part, or
nullwhen the URI string is not compliant
-
getTargetUriFromRequest
protected final java.lang.String getTargetUriFromRequest(javax.servlet.http.HttpServletRequest request)
Creates a RFC-6454 comparable URI from therequestrequested resource.- Parameters:
request- the incoming request- Returns:
- only the scheme://host[:port] part, or
nullwhen the origin string is not compliant
-
whitelistedHandler
protected void whitelistedHandler(javax.servlet.http.HttpServletRequest request, java.lang.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 requestorigin- the contents of theOriginHTTP headerpage- the page that is targeted with this request
-
onWhitelisted
protected void onWhitelisted(javax.servlet.http.HttpServletRequest request, java.lang.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 requestorigin- the contents of theOriginHTTP headerpage- the page that is targeted with this request
-
matchingOrigin
protected void matchingOrigin(javax.servlet.http.HttpServletRequest request, java.lang.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 requestorigin- the contents of theOriginHTTP headerpage- the page that is targeted with this request
-
onMatchingOrigin
protected void onMatchingOrigin(javax.servlet.http.HttpServletRequest request, java.lang.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 requestorigin- the contents of theOriginHTTP headerpage- the page that is targeted with this request
-
allowHandler
protected void allowHandler(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toALLOW.- Parameters:
request- the requestorigin- the contents of theOriginHTTP header, may benullor emptypage- the page that is targeted with this request
-
onAllowed
protected void onAllowed(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toALLOW.- Parameters:
request- the requestorigin- the contents of theOriginHTTP header, may benullor emptypage- the page that is targeted with this request
-
suppressHandler
protected void suppressHandler(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toSUPPRESS.- Parameters:
request- the requestorigin- the contents of theOriginHTTP header, may benullor emptypage- the page that is targeted with this request
-
onSuppressed
protected void onSuppressed(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toSUPPRESSED.- Parameters:
request- the requestorigin- the contents of theOriginHTTP header, may benullor emptypage- the page that is targeted with this request
-
abortHandler
protected void abortHandler(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toABORT.- Parameters:
request- the requestorigin- the contents of theOriginHTTP header, may benullor emptypage- the page that is targeted with this request
-
onAborted
protected void onAborted(javax.servlet.http.HttpServletRequest request, java.lang.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 (noOriginActionorconflictingOriginAction) is set toABORTED.- Parameters:
request- the requestorigin- the contents of theOriginHTTP header, may benullor emptypage- the page that is targeted with this request
-
-