Class CsrfPreventionFilter

java.lang.Object
org.camunda.bpm.webapp.impl.security.filter.CsrfPreventionFilter
All Implemented Interfaces:
jakarta.servlet.Filter

public class CsrfPreventionFilter extends Object implements 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
    Modifier and Type
    Field
    Description
     
    protected final Set<String>
     
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
     
    void
    doFilter(jakarta.servlet.ServletRequest servletRequest, jakarta.servlet.ServletResponse servletResponse, jakarta.servlet.FilterChain filterChain)
     
    protected boolean
    doSameOriginStandardHeadersVerification(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response)
    Validates if the Origin/Referer header matches the provided target origin.
    protected boolean
    doTokenValidation(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 String
    Generate a one-time token for authenticating subsequent requests.
    protected String
    getCookiePath(jakarta.servlet.http.HttpServletRequest request)
     
    int
     
     
     
    void
    init(jakarta.servlet.FilterConfig filterConfig)
     
    protected boolean
    isNonModifyingRequest(jakarta.servlet.http.HttpServletRequest request)
    Determine if the request a non-modifying request.
    protected void
    setCSRFToken(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response)
    Generates a new CSRF Token which is persisted in the session.
    void
    setDenyStatus(int denyStatus)
    Sets the response status code that is used to reject denied request.
    void
    setEntryPoints(String entryPoints)
    Entry points are URLs that will not be tested for the presence of a valid token.
    void
    setRandomClass(String randomClass)
    Sets the name of the class to use to generate tokens.
    void
    setTargetOrigin(String targetOrigin)
    Target origin is the application expected deployment domain, i.e.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

  • Constructor Details

    • CsrfPreventionFilter

      public CsrfPreventionFilter()
  • Method Details

    • init

      public void init(jakarta.servlet.FilterConfig filterConfig) throws jakarta.servlet.ServletException
      Specified by:
      init in interface jakarta.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:
      doFilter in interface jakarta.servlet.Filter
      Throws:
      IOException
      jakarta.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

      protected String getCookiePath(jakarta.servlet.http.HttpServletRequest request)
    • getTargetOrigin

      public URL getTargetOrigin()
    • setTargetOrigin

      public void setTargetOrigin(String targetOrigin) throws MalformedURLException
      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

      public void setEntryPoints(String entryPoints)
      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

      public String getRandomClass()
    • setRandomClass

      public void setRandomClass(String randomClass)
      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:
      destroy in interface jakarta.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

      protected String generateCSRFToken()
      Generate a one-time token for authenticating subsequent requests.
      Returns:
      the generated token