javacsrfowasp

Blank Pages and Responses when using OWASP CSRF Guard


I am trying to implement the OWASP CSRF Guard in a web application that I am updating (written in Java 17, running on a tomcat 10.1.25 server). We had been using the ESAPI library, but since we only used 6 unique methods from it, we've decided to use smaller libraries. From all the research I've done, I really only need to use the OWASP Java HTML Sanitizer and the OWASP CSRF Guard. I got the HTML Sanitizer implemented with no issues, but I can't seem to resolve some things with the CSRF Guard.

I have been trying to read and apply the example code I've found:

but I must not be understanding it and applying it correctly. This is what happens:

  1. I run my application (from Eclipse)
  2. the server starts up with no issues (I see the output from the csrf guard config)
  3. the web app opens (but images and css files do not load)
  4. I attempt to log into the web app
  5. the login servlet is initialized, but the doPost() method is not run
  6. it brings me to a blank page

Sometimes it would bring me to a blank page immediately after starting the application. There were no errors in any logs or in the browser console and all server responses were 200, but with blank files.

My web.xml looks like:

  <context-param>
    <param-name>Owasp.CsrfGuard.Config</param-name>
    <param-value>WEB-INF/csrfguard.properties</param-value>
  </context-param>
  
  <listener>
    <listener-class>org.owasp.csrfguard.CsrfGuardServletContextListener</listener-class>
  </listener>
  
  <listener>
    <listener-class>org.owasp.csrfguard.CsrfGuardHttpSessionListener</listener-class>
  </listener>
  
  <filter>
    <filter-name>AccessFilter</filter-name>
    <filter-class>wy.web.app.security.AccessFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>AccessFilter</filter-name>
    <url-pattern>/*</url-pattern> <!-- */ -->
  </filter-mapping>
  
  <filter>
    <filter-name>CSRFGuard</filter-name>
    <filter-class>org.owasp.csrfguard.CsrfGuardFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>CSRFGuard</filter-name>
    <url-pattern>/*</url-pattern> <!-- */ -->
  </filter-mapping>
  
  <servlet>
    <servlet-name>JavaScriptServlet</servlet-name>
    <servlet-class>org.owasp.csrfguard.servlet.JavaScriptServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>JavaScriptServlet</servlet-name>
    <url-pattern>/JavaScriptServlet</url-pattern>
  </servlet-mapping>
    
  <session-config>
    <session-timeout>30</session-timeout>
  </session-config>
  <welcome-file-list>
    <welcome-file>login.jsp</welcome-file>
  </welcome-file-list>

My csrfguard.properties file is like:

org.owasp.csrfguard.configuration.provider.factory = org.owasp.csrfguard.config.PropertiesConfigurationProviderFactory
org.owasp.csrfguard.Enabled = true

# have test both "true" and "false"
org.owasp.csrfguard.ValidateWhenNoSessionExists = true

org.owasp.csrfguard.TokenLength = 32
org.owasp.csrfguard.TokenName = OWASP-CSRFTOKEN
org.owasp.csrfguard.SessionKey = OWASP-CSRFTOKEN
org.owasp.csrfguard.PRNG = SHA1PRNG
org.owasp.csrfguard.PRNG.Provider = SUN

org.owasp.csrfguard.Ajax = true

org.owasp.csrfguard.LogicalSessionExtractor = org.owasp.csrfguard.session.SessionTokenKeyExtractor

org.owasp.csrfguard.JavascriptServlet.sourceFile = WEB-INF/Owasp.CsrfGuard.js
org.owasp.csrfguard.JavascriptServlet.domainStrict = false
org.owasp.csrfguard.JavascriptServlet.cacheControl = private, maxage=28800, no-cache, no-store, must-revalidate
org.owasp.csrfguard.JavascriptServlet.refererPattern = .*
# have test both "true" and "false"
org.owasp.csrfguard.JavascriptServlet.refererMatchProtocol = false
# have test both "true" and "false"
org.owasp.csrfguard.JavascriptServlet.refererMatchDomain = false
org.owasp.csrfguard.JavascriptServlet.injectIntoForms = true
org.owasp.csrfguard.JavascriptServlet.injectGetForms = true
org.owasp.csrfguard.JavascriptServlet.injectFormAttributes = true
org.owasp.csrfguard.JavascriptServlet.injectIntoAttributes = true
org.owasp.csrfguard.JavascriptServlet.injectIntoDynamicNodes = false
org.owasp.csrfguard.JavascriptServlet.xRequestedWith = OWASP CSRFGuard Project
org.owasp.csrfguard.JavascriptServlet.UnprotectedExtensions = js, css, gif, png, ico, jpg

org.owasp.csrfguard.configOverlay.hierarchy = file:WEB-INF/csrfguard.properties

# Mark the login page as unprotected, at least for testing
org.owasp.csrfguard.unprotected.Login = %servletContext%/login.jsp
org.owasp.csrfguard.unprotected.Error = %servletContext%/error.jsp

# Actions to perform when an attack is detected
# 1. Log the information
org.owasp.csrfguard.action.Log = org.owasp.csrfguard.action.Log
org.owasp.csrfguard.action.Log.Message = Potential cross-site request forgery (CSRF) attack thwarted (user:%user%, ip:%remote_ip%, method:%request_method%, uri:%request_uri%, error:%exception_message%)
# 2. Rotate the token; not supported with AJAX
#org.owasp.csrfguard.action.Rotate = org.owasp.csrfguard.action.Rotate
# 3. Invalidate the token that was misused
#org.owasp.csrfguard.action.Invalidate=org.owasp.csrfguard.action.Invalidate
# 4. Redirect the user/hacker to a specific page
#org.owasp.csrfguard.action.Redirect = org.owasp.csrfguard.action.Redirect
#org.owasp.csrfguard.action.Redirect.Page = /Owasp.CsrfGuard.Test/error.html
org.owasp.csrfguard.Logger = org.owasp.csrfguard.log.JavaLogger
org.owasp.csrfguard.log.JavaLogger.level = TRACE
org.owasp.csrfguard.Config.Print = true
org.owasp.csrfguard.forceSynchronousAjax = true

Why doesn't the next page load? Why are there no errors?


Solution

  • I found the answer to this question while writing it! In #5 of the process I described, I remembered seeing something in other's csrfguard.properties files. It turns out that defining the org.owasp.csrfguard.ProtectedMethods is required. Since it was commented out in CSRFGuard's property file, I thought there were some default settings for it--but apparently not! Setting it to POST fixed the issue!

    I also think that if I had set up the CSRFGuard error page, I may have noticed this issue sooner; maybe something like

    org.owasp.csrfguard.action.Redirect = org.owasp.csrfguard.action.Redirect
    org.owasp.csrfguard.action.Redirect.Page = %servletContext%/error.html