1. 项目概述为什么Java安全审计绕不开Filter干了这么多年Java开发和安全审计我越来越觉得Filter这玩意儿就像你家小区门口的保安。平时开发的时候你可能随手写个WebFilter(/*)就完事了觉得它就是个简单的“看门大爷”检查一下登录状态、记录个日志。但真到了做安全审计、渗透测试或者代码审计的时候你会发现这个“大爷”要是没管好或者他记的“访客名单”白名单有漏洞整个系统的“后门”可能就敞开了。最近带新人做项目审计又遇到了几起因为Filter配置不当导致的权限绕过案例。有直接通过../跳目录访问后台的有利用分号;截断绕过后缀检查的甚至还有因为Spring MVC路径匹配的“容错”特性多一个/就直接进了管理接口的。这些问题单看代码逻辑似乎没问题但组合起来就是致命漏洞。所以我决定把这些年踩过的坑、审计过的案例以及如何从“零基础”到能独立审计一套Web框架的Filter安全系统地梳理出来。这篇文章不会只讲理论我会用大量我亲手调试过的代码案例带你一步步拆解Filter的权限控制逻辑看看攻击者是怎么“骗过”保安的而我们又该如何写出更健壮的“安保系统”。无论你是刚入门Java Web安全的新手想理解权限绕过的基本原理还是有一定经验的开发者想提升自己代码的安全水位或者是专职的安全工程师需要一套系统的审计方法论这篇内容都会让你有收获。我们会从最基础的Servlet/Filter API讲起逐步深入到Spring Security、Shiro等框架的底层交互最后形成一套可复用的审计清单。目标就一个让你彻底搞懂Filter安全收藏这一篇以后遇到相关问题都能快速定位和解决。2. Filter权限控制的核心原理与常见漏洞模式要绕过Filter首先你得知道Filter是怎么工作的。很多开发者在实现权限控制时对HttpServletRequest里几个获取路径的方法区别模棱两可这就是漏洞的根源。2.1 关键API辨析requestURI、requestURL与servletPath这是最容易出问题的地方。我们写个最简单的Servlet和Filter来演示。WebServlet(/api/v1/user/profile) public class UserProfileServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.getWriter().write(User Profile Data); } } WebFilter(/*) public class SecurityFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String requestURI req.getRequestURI(); // 重点1 StringBuffer requestURL req.getRequestURL(); // 重点2 String servletPath req.getServletPath(); // 重点3 String pathInfo req.getPathInfo(); // 重点4 System.out.println(requestURI: requestURI); System.out.println(requestURL: requestURL); System.out.println(servletPath: servletPath); System.out.println(pathInfo: pathInfo); // 假设我们只允许访问 /api/v1/public/ 下的资源 if (!requestURI.startsWith(/api/v1/public/)) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, Access Denied); return; } chain.doFilter(request, response); } }部署后我们分别用几个特殊的请求来访问/api/v1/user/profile看看输出正常请求GET /api/v1/user/profilerequestURI: /api/v1/user/profilerequestURL: http://localhost:8080/api/v1/user/profileservletPath: /api/v1/user/profilepathInfo: null结果被Filter拦截返回403。路径回溯../绕过尝试GET /api/v1/public/../user/profilerequestURI: /api/v1/public/../user/profile关键requestURL: http://localhost:8080/api/v1/public/../user/profileservletPath: /api/v1/user/profile关键Servlet容器已标准化pathInfo: null结果requestURI以/api/v1/public/开头Filter放行但最终servletPath解析为/api/v1/user/profile请求成功到达目标Servlet。漏洞产生。分号截断绕过尝试GET /api/v1/public/;profilerequestURI: /api/v1/public/;profilerequestURL: http://localhost:8080/api/v1/public/;profileservletPath: /api/v1/public/关键分号后的内容被当作路径参数不影响servletPathpathInfo: null结果requestURI以/api/v1/public/开头Filter放行。Servlet容器在处理映射时会忽略分号后的内容因此仍然尝试寻找映射到/api/v1/public/的Servlet如果找不到则返回404。但如果我们请求的是/api/v1/public/;../user/profile情况会更复杂。核心要点request.getRequestURI()返回的是未经标准化Normalize的URI它包含了原始请求中的../、;等特殊字符。而request.getServletPath()返回的是经过Servlet容器标准化处理后的路径../会被解析;会被当作参数分隔符截断。如果你的权限判断基于requestURI而Servlet映射基于servletPath两者不一致就会导致绕过。2.2 四种经典的Filter权限绕过漏洞模式基于上面的API差异攻击者常用的绕过手法可以归纳为四类模式一路径回溯Directory Traversal绕过漏洞代码特征Filter中使用requestURI.startsWith(“/white/path”)或requestURI.contains(“/white/path”)进行白名单校验。攻击Payload/white/path/../../admin/secret.do原理requestURI校验时字符串以/white/path开头通过。但Servlet容器在路由时会将/white/path/../../admin/secret.do标准化为/admin/secret.do从而访问到受保护资源。审计技巧全局搜索getRequestURI()检查后续的字符串匹配逻辑startsWith,endsWith,contains,equals是否直接用于权限判断而未做标准化处理。模式二分号;截断绕过漏洞代码特征Filter中使用requestURI.endsWith(“.do”)或requestURI.endsWith(“.action”)来识别需要鉴权的动态请求。攻击Payload/admin/secret.do;xxx或/white/path/;../admin/secret.do原理requestURI以.do;xxx结尾不满足.do结尾的规则可能被放行或走入默认逻辑。Servlet容器会忽略;及其后的内容视为路径参数path parameter因此实际访问的仍是/admin/secret.do。审计技巧搜索endsWith检查是否用于过滤静态资源或定义拦截规则。同时注意在Spring MVC中分号有特殊含义需结合框架行为分析。模式三多重斜杠//与URL编码绕过漏洞代码特征Filter中使用requestURI.equals(“/exact/path”)进行精确路径匹配。攻击Payload多重斜杠//exact/path或/exact//pathURL编码/%65%78%61%63%74/%70%61%74%68(对应/exact/path)原理多重斜杠某些容器或框架如Spring MVC with/**映射会对路径进行合并处理//exact/path会被等价为/exact/path但字符串equals比较失败导致绕过。URL编码Filter获取的requestURI是未解码的而容器在后续路由时会进行URL解码。如果Filter用未解码的字符串做匹配而攻击者提交编码后的路径就会绕过检查。审计技巧检查精确匹配equals的使用场景。搜索getRequestURI()后是否调用了URLDecoder.decode()。关注框架的路径规范化配置。模式四后缀与路径参数组合绕过漏洞代码特征框架如Struts2、Spring MVC有特定的后缀映射如.action,.do或路径匹配模式。攻击Payload/admin/secret.action/或/admin/secret.do/原理某些框架的路径匹配逻辑是“前缀匹配”或存在容错机制。例如一个映射为/admin/*的Filter可能因为配置问题对/admin/secret.do/的请求处理不当。或者Spring MVC的RequestMapping(“/admin/secret”)可能会默认处理/admin/secret/的请求但Filter的规则可能没覆盖这种情况。审计技巧需要理解项目所用Web框架的URL映射机制。对比web.xml中Filter的url-pattern与Servlet/Controller的映射规则是否存在差异。3. 从黑盒到白盒系统的Filter安全审计方法论知道了漏洞模式我们如何对一个系统进行全面的Filter安全审计呢我总结了一套从外部探测到内部代码审查的流程适用于渗透测试和代码审计两种场景。3.1 黑盒探测模糊测试与边界案例构造在没有代码的情况下我们可以通过构造大量异常请求观察系统响应来探测潜在的Filter绕过点。第一步信息收集与端点枚举使用工具如Burp Suite的Target Site map或爬虫收集所有应用端点URL。特别关注登录接口、注销接口、静态资源路径、API文档路径、错误页面路径。这些通常是白名单的候选。第二步针对性的Payload测试根据收集的端点系统性地注入绕过Payload。我通常会准备一个测试清单用Burp Intruder或自定义脚本跑一遍。测试类型测试Payload示例针对目标/admin/list预期观察点路径回溯/public/../admin/list/images/../../admin/list/login/../../admin/list是否返回了本应鉴权的内容状态码是否为200而非403/302分号截断/admin/list;.js/admin/list;/public/;../admin/list同上。注意响应体内容是否与正常访问一致。多重斜杠//admin/list/admin//list/admin///list后缀变异/admin/list/(末尾加斜杠)/admin/list.json(加其他后缀)/admin/list.action(改为框架后缀)URL编码/%61%64%6d%69%6e/%6c%69%73%74(全编码)/admin/%6c%69%73%74(部分编码)/admin%2flist(编码斜杠)大小写混淆/ADMIN/list/Admin/List某些大小写敏感/不敏感的配置可能导致绕过。HTTP方法篡改将POST /admin/add改为GET /admin/addFilter可能只拦截了POST没拦截GET。参数污染/admin/list?tokenxxxtokenyyy处理多个同名参数时Filter和后台逻辑可能取值不一致。第三步逻辑流程探测步骤绕过跳过前置步骤直接访问后续接口。例如支付流程为A - B - C尝试直接访问C。引用检查绕过修改HTTP请求头中的Referer尝试绕过基于Referer的简单校验。直接对象引用IDOR 修改请求参数中的ID如/user/123/profile改为/user/456/profile测试Filter是否只验证了路径未验证数据归属。实操心得黑盒测试时重点观察响应差异。一个成功的绕过其响应状态码、响应体长度、内容关键词通常与未授权访问被拒时不同而与正常授权访问相似。配合Burp的Comparer工具进行差异对比非常有效。3.2 白盒代码审计关键代码定位与分析拿到代码后审计效率会大大提高。我们的目标是快速定位所有Filter和权限校验相关代码。第一步全局搜索定位Filter类关键词javax.servlet.Filterimplements FilterWebFilterextends OncePerRequestFilter(Spring)filter-mapping(在web.xml中)ShiroFilterFactoryBean(Apache Shiro)SecurityFilterChain(Spring Security)工具IDE的全局搜索ShiftShift in IntelliJ IDEA / CtrlH in Eclipse或grep -r命令。第二步分析Filter的执行顺序与作用范围查看web.xml中filter-mapping的顺序或WebFilter的filterName及Order注解。顺序错误可能导致安全Filter被绕过。确认每个Filter的url-pattern或WebFilter(“/*”)。特别注意是否有Filter使用了/*但内部又对某些路径做了chain.doFilter()提前放行这里是逻辑重点。第三步深入审计核心校验逻辑对找到的每一个Security Filter进行如下检查路径获取方式 是request.getRequestURI()还是request.getServletPath()或者是Spring提供的AntPathMatcher匹配路径标准化 在比较前是否对路径进行了规范化处理例如调用org.springframework.util.StringUtils.cleanPath(path)或javax.servlet.http.HttpServletRequest#getServletPath()。白名单逻辑 检查白名单列表是否完整是否存在像/public/这样的目录允许了/public/../admin的绕过白名单匹配是startsWith、equals还是antMatchers黑名单逻辑 检查黑名单如拦截.do,.action是否容易被分号、空格、换行符截断绕过会话与权限验证 验证用户身份和权限时是从Session中获取对象并进行了非空判断和角色校验还是仅仅判断了Session中某个标志是否存在后者可能被通过设置一个空值绕过。框架特定配置 如果使用了Spring Security检查HttpSecurity配置中antMatchers()的顺序是否正确更具体的规则是否写在了更通用的规则前面是否使用了permitAll()第四步审计工具链辅助静态代码分析工具SAST 如SonarQube、Fortify、Checkmarx。它们可以自动识别一些常见的漏洞模式如“路径遍历”CWE-22、“权限绕过”CWE-285。但工具报告需要人工复核误报和漏报都存在。代码搜索神器grep配合正则表达式依然强大。例如搜索所有使用requestURI进行endsWith判断的代码grep -r “getRequestURI.*endsWith” --include”*.java” .4. 主流安全框架下的Filter安全审计实战现代Java Web项目很少裸用Servlet Filter做权限控制更多的是集成Spring Security或Apache Shiro。这些框架功能强大但配置不当同样会引入绕过风险。我们分别来看。4.1 Spring Security Filter Chain审计要点Spring Security的本质就是一系列Filter组成的责任链。它的配置方式古老的XML和现代的基于Lambda的DSL影响着安全边界。漏洞场景一配置顺序错误导致绕过这是Spring Security最常见的配置失误之一。Configuration EnableWebSecurity public class InsecureSecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authz - authz .requestMatchers(/admin/**).hasRole(ADMIN) // 规则A管理后台需ADMIN角色 .requestMatchers(/**).permitAll() // 规则B其他所有请求放行 ) .formLogin(withDefaults()); return http.build(); } }问题规则B (/**) 比规则A (/admin/**)更通用且放在了后面。Spring Security的匹配规则是从上到下第一个匹配的规则生效。因此一个访问/admin/list的请求会先被规则B匹配从而被permitAll()放行根本不会走到规则A进行角色检查。修复将更具体的规则放在前面更通用的规则放在后面。.requestMatchers(/public/**, /login, /error).permitAll() // 明确的白名单放前面 .requestMatchers(/admin/**).hasRole(ADMIN) // 权限规则 .anyRequest().authenticated() // 其他所有请求需要认证放在最后漏洞场景二antMatchers与mvcMatchers的差异antMatchers(“/user”) 默认情况下只匹配/user不匹配/user/。mvcMatchers(“/user”) 基于Spring MVC的RequestMapping逻辑会匹配/user、/user/、/user.*如/user.json。 如果Filter链用antMatchers而Controller用RequestMapping(“/user”)攻击者访问/user/就可能绕过Filter的检查。审计建议在Spring Security 5.8版本推荐使用requestMatchers替代antMatchers和mvcMatchers其默认行为更智能。检查旧配置中是否存在这种不匹配。漏洞场景三忽略静态资源时的路径遍历http .authorizeHttpRequests(authz - authz .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() .anyRequest().authenticated() );PathRequest.toStaticResources().atCommonLocations()会放行像/css/,/js/,/images/等路径。但如果攻击者构造请求/images/../WEB-INF/web.xml而你的应用没有额外配置防止路径遍历Spring Boot默认是防的就可能读取到敏感文件。审计建议确认静态资源放行规则是否过于宽泛。检查服务器如Tomcat的conf/web.xml中是否配置了DefaultServlet的readonly为true以及是否设置了allowLinking为false防止符号链接攻击。4.2 Apache Shiro Filter Chain审计要点Shiro通过ShiroFilterFactoryBean配置URL路径的拦截规则其匹配顺序同样关键。漏洞场景一anon与authc的顺序[urls] /admin/** authc, roles[admin] # 需要认证和admin角色 /** anon # 匿名访问和Spring Security一样更通用的/** anon放在后面会导致/admin/**规则失效。修复调整顺序通用规则在前具体规则在后Shiro是自上而下匹配首次匹配成功即返回。[urls] /static/** anon /login anon /logout logout /admin/** authc, roles[admin] /** authc # 其他所有请求需要认证漏洞场景二Shiro的路径匹配与特殊字符Shiro默认使用PathMatchingFilterChainResolver它支持Ant风格的匹配。但需要关注上下文路径Context Path 如果应用部署在/myapp下Shiro的配置路径通常需要包含上下文路径或者通过filterChainDefinitionMap动态设置。URL解码问题 早期某些Shiro版本存在URL解码不一致问题攻击者通过双重编码可能绕过。需确认Shiro版本并检查是否有相关CVE。Spring Boot集成 在Spring Boot中Shiro的Filter可能因为Spring Boot的自动配置如对于/error端点的处理而产生意想不到的交互需要测试验证。审计清单打开shiro.ini或对应的Java配置类检查[urls]部分。确认规则顺序是否符合“先具体后通用”或“先白名单后鉴权”的原则。搜索项目中是否自定义了Filter或AuthenticatingFilter检查其isAccessAllowed或onAccessDenied方法逻辑。检查是否有接口直接使用了RequiresPermissions、RequiresRoles注解但对应的URL却没有在Filter链中配置拦截导致注解失效。4.3 自定义Filter的进阶安全编码实践即使使用了安全框架有时仍需要编写自定义Filter处理特定逻辑。以下是编写健壮Filter的几个黄金法则法则一使用标准化后的路径进行判断这是杜绝../和;绕过的根本方法。public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) res; // 最佳实践使用 getServletPath() 或进行标准化 String path request.getServletPath(); String pathInfo request.getPathInfo(); String requestPath path (pathInfo ! null ? pathInfo : ); // 或者使用工具类进行标准化Spring提供了 // String requestPath new UrlPathHelper().getPathWithinApplication(request); // 再进行你的白名单/权限判断 if (isPublicResource(requestPath)) { chain.doFilter(request, response); return; } // ... 权限校验 }法则二对于白名单使用精确匹配或前缀匹配长度验证// 不安全的做法 if (requestPath.startsWith(/public/)) { // 可能被 /public/../admin 绕过 } // 改进做法1精确匹配适用于具体文件 SetString publicUrls Set.of(/login, /logout, /error); if (publicUrls.contains(requestPath)) { chain.doFilter(request, response); return; } // 改进做法2前缀匹配 验证后续字符适用于目录 if (requestPath.startsWith(/static/)) { // 确保 /static/ 后面没有 .. String remainingPath requestPath.substring(/static/.length()); if (remainingPath.contains(..)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, Path traversal attempt detected.); return; } chain.doFilter(request, response); return; }法则三统一在Filter入口处进行解码和规范化// 在Filter最开始对路径进行一次清洗和验证 String requestUri request.getRequestURI(); try { // 1. URL解码注意防止双重解码 String decodedUri URLDecoder.decode(requestUri, StandardCharsets.UTF_8.name()); // 2. 规范化路径移除 ./ 和 ../ String normalizedPath Paths.get(decodedUri).normalize().toString(); // 注意Paths.get会处理文件系统路径对于Web路径需确保不以/开头或使用自定义的规范化函数 // 3. 验证规范化后的路径是否以..开头尝试跳出根目录 if (normalizedPath.startsWith(..) || normalizedPath.contains(/../)) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, Invalid path.); return; } // 将处理后的路径存入request属性供后续逻辑使用 request.setAttribute(CLEANED_REQUEST_PATH, normalizedPath); } catch (IllegalArgumentException e) { // 无效的编码 response.sendError(HttpServletResponse.SC_BAD_REQUEST, Invalid URL encoding.); return; } // 后续逻辑使用 request.getAttribute(CLEANED_REQUEST_PATH)法则四谨慎处理Forward和IncludeFilter不仅拦截外部请求也可能拦截服务器内部的RequestDispatcher.forward()和include()。如果你的权限Filter不应该拦截内部转发需要在逻辑中加以区分if (request.getDispatcherType() DispatcherType.FORWARD || request.getDispatcherType() DispatcherType.INCLUDE) { // 对于内部转发直接放行或者执行不同的逻辑 chain.doFilter(request, response); return; } // 只处理外部请求(DispatcherType.REQUEST)5. 实战审计案例剖析一个真实的权限绕过漏洞我们来看一个我曾在内部代码审计中发现的复合型漏洞。这个案例融合了路径回溯、配置顺序错误和权限验证逻辑缺陷。系统背景一个Spring Boot Spring Security的管理系统部分静态资源交由Nginx处理但部分API接口由应用自身提供下载功能。漏洞代码片段Spring Security 配置 (有误)Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers(/download/**).authenticated() // 规则1下载需认证 .antMatchers(/api/admin/**).hasRole(ADMIN) // 规则2管理员API .antMatchers(/**).permitAll() // 规则3其他全部放行错误位置 .and() .formLogin(); } }自定义下载ServletWebServlet(/download/*) public class FileDownloadServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { String filePath req.getPathInfo(); // 获取 /download/ 后面的部分如 “/../conf/application.yml” File file new File(BASE_DIR, filePath); // ... 发送文件内容 } }漏洞复现与原理分析配置顺序绕过由于规则3 (/**) 放在了最后且/**匹配所有请求。因此访问/api/admin/list时Spring Security会先匹配到规则3 (/**)从而被permitAll()放行管理员权限检查形同虚设。路径遍历漏洞即使通过了认证访问/download/../conf/application.yml时req.getPathInfo()返回/../conf/application.yml。File构造函数拼接路径后可能指向应用配置目录导致敏感文件泄露。这里Filter或Servlet没有对filePath进行../的检查和过滤。组合利用攻击者首先利用配置绕过直接以匿名身份访问本应需要认证的/download/接口再利用该接口的路径遍历漏洞读取系统任意文件。修复方案调整Spring Security规则顺序.antMatchers(/public/**, /error).permitAll() .antMatchers(/download/**).authenticated() // 认证用户可下载 .antMatchers(/api/admin/**).hasRole(ADMIN) .anyRequest().authenticated() // 其他所有请求需要认证在下载Servlet中加固路径校验String filePath req.getPathInfo(); if (filePath null) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } // 标准化路径防止 ../ Path normalizedPath Paths.get(BASE_DIR).resolve(filePath).normalize(); // 检查标准化后的路径是否仍在基准目录下 if (!normalizedPath.startsWith(Paths.get(BASE_DIR).toAbsolutePath())) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, Access denied.); return; } File file normalizedPath.toFile();这个案例告诉我们安全是一个整体。Filter链的配置、业务逻辑的编码、甚至服务器的部署方式任何一个环节的疏忽都可能被串联利用形成严重的漏洞。6. 防御体系构建与审计 checklist最后我将多年的经验总结成一份可操作的防御清单和审计Checklist。你可以拿着它去审视自己的项目或者用于代码审计工作。6.1 开发阶段安全编码最佳实践路径处理统一化在Filter或拦截器的最入口使用request.getServletPath()结合request.getPathInfo()或使用Spring的UrlPathHelper.getPathWithinApplication(request)来获取标准化后的请求路径。禁止直接使用request.getRequestURI()进行安全决策。白名单优于黑名单尽可能使用精确的白名单来放行公开资源。如果必须使用黑名单要意识到其不完整性并配合其他校验。顺序至关重要在配置安全规则Spring Security的antMatchers、Shiro的[urls]、自定义Filter的web.xml顺序时牢记“先具体后通用”原则。将最精确的匹配规则放在前面最宽松的如/**放在最后。规范化与验证对所有从客户端获取的、用于文件系统操作的路径参数必须进行标准化normalize()和路径穿越检查确保结果路径在预期根目录内。框架特性了然于胸深入了解你使用的Web框架Spring MVC、Struts2等和容器Tomcat、Jetty的URL映射、解码、规范化行为差异。例如Tomcat的allowLinking属性Spring MVC的useTrailingSlashMatch配置。定期依赖检查使用OWASP Dependency-Check、Maven的versions:display-dependency-updates等工具定期检查项目依赖特别是Shiro、Spring Security等安全组件是否存在已知漏洞。6.2 审计阶段核心Checklist当你审计一个Java Web应用时可以按以下清单逐项检查Filter配置与映射[ ] 检查web.xml或WebFilter中所有Filter的url-pattern或value确认其拦截范围是否符合预期。[ ] 分析Filter的执行顺序是否存在安全Filter被业务Filter绕过的情况[ ] 如果使用了Spring Security检查HttpSecurity配置中authorizeRequests()的规则顺序是否正确具体通用[ ] 如果使用了Shiro检查[urls]部分的规则顺序是否正确路径获取与校验逻辑[ ] 全局搜索getRequestURI()审查所有使用它的地方是否直接用于startsWith(),endsWith(),contains(),equals()等字符串比较是否未做标准化处理[ ] 是否使用了getServletPath()或getPathInfo()是否正确处理了null值[ ] 代码中是否存在对../,;,//,%2e%2e(URL编码的..) 等特殊字符的过滤过滤逻辑是否可以被绕过例如只过滤../不过滤..\或URL编码形式[ ] 白名单路径的匹配逻辑是否严谨例如白名单/public/是否可能被/public/../admin绕过会话与权限验证[ ] 权限校验Filter中是从Session的哪个属性获取用户信息是否做了非空判断和类型转换[ ] 对于角色或权限的校验是简单的字符串相等判断还是调用了框架的权威方法如hasRole()[ ] 是否有接口或页面看似需要权限但其对应的URL却没有被任何安全Filter覆盖遗漏配置框架特定风险点[ ]Spring MVC 检查RequestMapping的路径与Filter拦截路径是否匹配是否使用了/**这样的通配符导致对静态资源或错误页面的处理出现意外[ ]Spring Boot 检查application.properties/yml中关于静态资源路径(spring.resources.static-locations)、错误页面(server.error.path)的配置是否会与安全规则冲突[ ]Apache Shiro 检查ShiroFilterFactoryBean的配置特别是filterChainDefinitions字符串。确认是否启用了anon,authc等默认Filter其顺序如何[ ]文件操作 搜索File,Path,Files.readAllBytes等文件操作相关代码检查路径参数是否用户可控是否进行了规范化与目录穿越检查部署与环境[ ] 应用服务器的配置如Tomcat的conf/web.xml中DefaultServlet的初始化参数是否安全readonly是否设为true[ ] 前端是否有可能构造特殊请求如通过img src”…”发起跨域请求来绕过某些基于Referer的简单校验安全是一个持续的过程没有一劳永逸的银弹。Filter作为请求进入应用的第一道关卡其安全性至关重要。希望这篇从原理到实战、从漏洞到防御的长文能帮你建立起对Java Web Filter安全的立体认知。下次当你编写或审查一段权限控制代码时不妨多问一句“如果请求路径里有个../或;会发生什么” 这份警惕性就是安全工程师最重要的素养。