Class CsrfPreventionFilter
java.lang.Object
org.eximeebpms.bpm.webapp.impl.security.filter.CsrfPreventionFilter
- All Implemented Interfaces:
jakarta.servlet.Filter
Provides basic CSRF protection implementing a Same Origin Standard Header verification (step 1)
and a Synchronization Token with a cookie-stored token on the front-end.
This token is called XSRF-TOKEN, generated by the server, sent in the first response as a Cookie, then stored as a client Cookie, and sent back as an HTTP header (X-XSRF-TOKEN) on subsequent requests.
Positive scenario:
Client Server
| |
| GET Fetch Request \| JSESSIONID
|---------------------------------| XSRF-TOKEN
| /| pair generation
|/Response to Fetch Request |
|---------------------------------|
JSESSIONID |\ |
XSRF-TOKEN | |
pair cached | POST Request with valid token \| JSESSIONID
| header |
|---------------------------------| XSRF-TOKEN
| /| pair validation
|/ Response to POST Request |
|---------------------------------|
|\ |
Negative scenario:
Client Server
| |
| POST Request without token | JSESSIONID
| header \| XSRF-TOKEN
|---------------------------------| pair validation
| /|
|/Request is rejected |
|---------------------------------|
|\ |
Client Server
| |
| POST Request with invalid token\| JSESSIONID
|---------------------------------| XSRF-TOKEN
| /| pair validation
|/Request is rejected |
|---------------------------------|
|\ |
Parts of this code were ported from the CsrfPreventionFilter class
of Apache Tomcat. Furthermore, the RestCsrfPreventionFilter class from
the same codebase was used as a guideline.- Author:
- Nikola Koevski
-
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoiddestroy()voiddoFilter(jakarta.servlet.ServletRequest servletRequest, jakarta.servlet.ServletResponse servletResponse, jakarta.servlet.FilterChain filterChain) protected booleandoSameOriginStandardHeadersVerification(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) Validates if the Origin/Referer header matches the provided target origin.protected booleandoTokenValidation(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) Validates the provided CSRF token value from the request with the session CSRF token value.protected StringGenerate a one-time token for authenticating subsequent requests.protected StringgetCookiePath(jakarta.servlet.http.HttpServletRequest request) intvoidinit(jakarta.servlet.FilterConfig filterConfig) protected booleanisNonModifyingRequest(jakarta.servlet.http.HttpServletRequest request) Determine if the request a non-modifying request.protected voidsetCSRFToken(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) Generates a new CSRF Token which is persisted in the session.voidsetDenyStatus(int denyStatus) Sets the response status code that is used to reject denied request.voidsetEntryPoints(String entryPoints) Entry points are URLs that will not be tested for the presence of a valid token.voidsetRandomClass(String randomClass) Sets the name of the class to use to generate tokens.voidsetTargetOrigin(String targetOrigin) Target origin is the application expected deployment domain, i.e. the domain name through which the webapps are accessed.
-
Field Details
-
entryPoints
-
cookieConfigurator
-
-
Constructor Details
-
CsrfPreventionFilter
public CsrfPreventionFilter()
-
-
Method Details
-
init
public void init(jakarta.servlet.FilterConfig filterConfig) throws jakarta.servlet.ServletException - Specified by:
initin interfacejakarta.servlet.Filter- Throws:
jakarta.servlet.ServletException
-
doFilter
public void doFilter(jakarta.servlet.ServletRequest servletRequest, jakarta.servlet.ServletResponse servletResponse, jakarta.servlet.FilterChain filterChain) throws IOException, jakarta.servlet.ServletException - Specified by:
doFilterin interfacejakarta.servlet.Filter- Throws:
IOExceptionjakarta.servlet.ServletException
-
doTokenValidation
protected boolean doTokenValidation(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) throws IOException Validates the provided CSRF token value from the request with the session CSRF token value.- Parameters:
request-response-- Returns:
- true if the token is valid
- Throws:
IOException
-
doSameOriginStandardHeadersVerification
protected boolean doSameOriginStandardHeadersVerification(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) throws IOException Validates if the Origin/Referer header matches the provided target origin.- Parameters:
request-response-- Returns:
- true if the values match
- Throws:
IOException
-
setCSRFToken
protected void setCSRFToken(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) Generates a new CSRF Token which is persisted in the session. How the token is forwarded to the client and how it will be persisted there is not covered by this method.- Parameters:
request-
-
getCookiePath
-
getTargetOrigin
-
setTargetOrigin
Target origin is the application expected deployment domain, i.e. the domain name through which the webapps are accessed. If nothing is set, the "Same Origin with Standard Headers" verification is not performed.- Parameters:
targetOrigin- The application's domain name together with the protocol and port (ex. http://example.com:8080)- Throws:
MalformedURLException
-
setEntryPoints
Entry points are URLs that will not be tested for the presence of a valid token. They are used to provide a way to navigate back to a protected application after navigating away from it. Entry points will be limited to HTTP GET requests and should not trigger any security sensitive actions.- Parameters:
entryPoints- Comma separated list of URLs to be configured as entry points.
-
getDenyStatus
public int getDenyStatus()- Returns:
- the response status code that is used to reject a denied request.
-
setDenyStatus
public void setDenyStatus(int denyStatus) Sets the response status code that is used to reject denied request. If none is set, the default value of 403 will be used.- Parameters:
denyStatus- HTTP status code
-
getRandomClass
-
setRandomClass
Sets the name of the class to use to generate tokens. The class must be an instance of `java.util.Random`. If not set, the default value of `java.security.SecureRandom` will be used.- Parameters:
randomClass- The name of the class
-
destroy
public void destroy()- Specified by:
destroyin interfacejakarta.servlet.Filter
-
isNonModifyingRequest
protected boolean isNonModifyingRequest(jakarta.servlet.http.HttpServletRequest request) Determine if the request a non-modifying request. A non-modifying request is one that is either a 'HTTP GET/OPTIONS/HEAD' request, or is allowed explicitly through the 'entryPoints' parameter in the web.xml- Returns:
- true if the request is a non-modifying request
-
generateCSRFToken
Generate a one-time token for authenticating subsequent requests.- Returns:
- the generated token
-