必须用过滤器+黑名单,因为@Valid注解仅校验格式而非内容安全,无法拦截onerror=alert(1)或' OR '1'='1等语义型攻击;过滤器工作在Servlet最前端,统一处理所有请求入口,并通过HTML解码、小写归一、正则匹配(含大小写不敏感与绕过变形)实现可靠防护。

在 Java Web 项目中,仅靠注解式参数校验(如 @NotBlank、@Pattern)无法覆盖 XSS 和 SQL 注入这类语义型攻击。真正有效的做法是:在请求进入业务逻辑前,用过滤器统一拦截所有参数,结合黑名单词库做预处理——不是替代参数校验,而是补上它缺失的“内容安全”一环。
为什么必须用过滤器+黑名单,而不是只靠 @Valid
注解校验只管格式,不管内容意图。比如:
- @Pattern(regexp = "^[a-zA-Z0-9_]+$") 能拦住 <script></script>,但拦不住 onerror=alert(1) 这种绕过正则的内联事件;
- @Size(max = 50) 对 admin'-- 或 1 or 1=1 完全无效。
而过滤器工作在 Servlet 层最前端,对所有 request.getParameter()、getParameterMap()、getInputStream() 等入口统一生效,不依赖 Controller 层是否加了注解。
黑名单词库要覆盖的关键攻击模式
词库不是简单列几个关键词,需按攻击类型分层设计:
-
XSS 相关:<script、<img、onerror、javascript:、eval(、document.cookie、location.href、
<iframe、<svg、expression( - SQL 注入相关:' or '1'='1、--、#、/*、*/、union select、insert into、drop table、delete from、xp_cmdshell、exec master、load_file、into outfile
-
通用绕过技巧:空格替换成 /**/、%20、$09;单引号替换成 %27;大小写混写(如
UnIoN SeLeCt);编码变形(如<script></script>)
过滤器中如何安全使用黑名单
直接 String.contains() 或 replaceAll() 易被绕过。正确做法是:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 对原始参数值先做 HTML 解码(防编码绕过),再转为小写统一比对
- 用
Pattern.compile("(?i)union\s+select|\bor\s+1=1|<script pattern.case_insensitive> 写正则,支持模糊匹配和空格容忍</script> - 匹配到敏感词时,不简单删除,而是替换为占位符(如
[BLOCKED])并记录日志,避免破坏业务字段长度校验 - 对 JSON 请求体(Content-Type: application/json),需解析后递归遍历所有字符串字段,不能只扫 query string
与 Spring Validation 协同工作的建议
过滤器做完清洗后,再进 Controller 层做注解校验。两者分工明确:
立即学习“Java免费学习笔记(深入)”;
- 过滤器负责“消毒”:把恶意字符转义或屏蔽,保证后续流程拿到的是干净字符串
- @Valid 负责“塑形”:验证非空、长度、格式、枚举范围等业务规则
- 若过滤器发现高危词(如
drop table),可直接返回 400 并中断请求,不交给后续校验
不复杂但容易忽略:黑名单必须定期更新,建议从 OWASP 的 XSS Cheat Sheet 和 SQLi Cheat Sheet 同步最新绕过模式,并加入项目自身历史攻击样本。

















