集成OWASP CSRF Guard后出现空白页及无响应问题排查
问题背景
基于Java 17、Tomcat 10.1.25的Web应用,替换ESAPI为OWASP Java HTML Sanitizer+CSRF Guard,前者集成正常,后者出现以下异常:
- 服务器启动正常(可见CSRF Guard配置日志)
- 页面可打开,但静态资源(图片、CSS等)无法加载
- 登录时Login Servlet初始化,但
doPost()未执行,跳转空白页 - 偶发性启动后直接显示空白页,日志/控制台无报错,所有响应码200但内容为空
配置文件
web.xml
<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>
csrfguard.properties
org.owasp.csrfguard.configuration.provider.factory = org.owasp.csrfguard.config.PropertiesConfigurationProviderFactory org.owasp.csrfguard.Enabled = true # 已测试true和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 = .* # 已测试true和false两种取值 org.owasp.csrfguard.JavascriptServlet.refererMatchProtocol = false # 已测试true和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 # 将登录页标记为未受保护,至少用于测试 org.owasp.csrfguard.unprotected.Login = %servletContext%/login.jsp org.owasp.csrfguard.unprotected.Error = %servletContext%/error.jsp # 检测到攻击时执行的操作 # 1. 记录信息 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. 轮换令牌;AJAX不支持此操作 #org.owasp.csrfguard.action.Rotate = org.owasp.csrfguard.action.Rotate # 3. 使被滥用的令牌失效 #org.owasp.csrfguard.action.Invalidate=org.owasp.csrfguard.action.Invalidate # 4. 将用户/攻击者重定向到指定页面 #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
排查与修复方案
1. 调整过滤器执行顺序
当前AccessFilter在CSRFGuardFilter之前执行,可能导致CSRF Guard的响应处理逻辑被拦截或截断。修改web.xml,将CSRFGuardFilter放在AccessFilter之前:
<!-- 先加载CSRFGuardFilter --> <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> <!-- 后加载自定义AccessFilter --> <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>
2. 全局排除静态资源保护
JavascriptServlet.UnprotectedExtensions仅针对JS Servlet的资源,需在csrfguard.properties中添加全局未保护规则,让静态资源跳过CSRF校验:
# 按后缀排除静态资源 org.owasp.csrfguard.unprotected.StaticFiles = %servletContext%/*.js, %servletContext%/*.css, %servletContext%/*.gif, %servletContext%/*.png, %servletContext%/*.ico, %servletContext%/*.jpg # 若静态资源存放在指定目录(如/static/),添加目录排除规则 org.owasp.csrfguard.unprotected.StaticDir = %servletContext%/static/*
3. 关闭无Session时的校验
当ValidateWhenNoSessionExists=true时,未登录状态(无Session)的请求会被强制校验,即使登录页标记为未保护,也可能存在规则匹配异常。暂时设置为false测试:
org.owasp.csrfguard.ValidateWhenNoSessionExists = false
4. 修正JS资源加载路径
若使用CSRF Guard自带的Owasp.CsrfGuard.js,无需手动放置在WEB-INF,改为从类路径加载(依赖包已包含):
org.owasp.csrfguard.JavascriptServlet.sourceFile = classpath:Owasp.CsrfGuard.js
5. 排查响应截断问题
检查Tomcat的localhost.log或应用日志(已开启TRACE级别),查看CSRF Guard是否有拦截记录。同时检查自定义AccessFilter是否存在修改响应输出流、提前关闭流的逻辑,导致响应内容无法正常输出。
6. 确认版本兼容性
Tomcat 10.1基于Jakarta EE 9.1规范,需使用CSRF Guard 4.0及以上版本(旧版本仅支持Java EE,存在Servlet API兼容问题)。
内容的提问来源于stack exchange,提问作者Izek H

