Spring Security 不防 SQL 注入,因其默认 Filter 不解析请求内容;须自定义 Filter 在 DispatcherServlet 前拦截,并分层防护:过滤器做初步关键字匹配,Controller 用 @Valid 校验,DAO 层禁用拼接、MyBatis 用 #{},动态 SQL 需白名单。

Spring Security 本身不处理 SQL 注入防护,它不解析 SQL、不拦截参数、也不重写查询逻辑。想靠 HttpSecurity 配置项或 FilterChain 默认行为防 SQL 注入,注定失败。
为什么不能依赖 Spring Security 的默认 filter 做 SQL 注入过滤
Spring Security 的核心 filter(如 UsernamePasswordAuthenticationFilter、ExceptionTranslationFilter)只关心认证授权流程,对请求体、查询参数、header 中是否含 UNION、SELECT、--、/* 等关键字完全无感知。它既不扫描原始请求内容,也不做字符串匹配式清洗。
- 所有“SQL 关键字拦截”必须由你自定义的
Filter在DispatcherServlet前完成 - Spring Security 的
FilterChainProxy虽然能插 filter,但它不提供开箱即用的注入检测能力 - 误配
http.addFilterBefore()却没真正实现校验逻辑,会给人“已防护”的错觉,反而更危险
SqlInjectFilter 必须在 DispatcherServlet 之前生效
真正起作用的过滤器必须注册在 Spring MVC 的入口之前,否则 request.getParameter() 或 request.getInputStream() 已被读取过一次,再读会抛 IllegalStateException。正确做法是让自定义 filter 实现 javax.servlet.Filter,并通过 @WebFilter 或 FilterRegistrationBean 显式声明顺序。
- 使用
FilterRegistrationBean时,设置setOrder(Ordered.HIGHEST_PRECEDENCE) - 不要在
doFilter()里直接调用request.getParameterMap()—— 它无法获取 JSON body 内容;需先判断Content-Type,对application/json手动读取并解析 - 关键字列表不能硬编码,应从配置中心或
@Value("${security.sql-inject.keywords}")加载,例如:select|union|insert|delete|drop|;|--|/\*|\*/|exec|execute|xp_
参数校验必须分层落地,不能只靠过滤器
过滤器只能拦住明显恶意流量(比如 URL 含 1' OR '1'='1),但无法识别语义等价的绕过写法(如用双写、编码、注释分隔)。真正的防护必须下沉到业务层:
- Controller 层强制使用
@Valid+@RequestBody,实体类字段加@Pattern、@Size、@NotBlank等约束 - DAO 层禁用任何形式的字符串拼接:
"WHERE name = '" + name + "'"是红线,必须用JdbcTemplate.query("...", new Object[]{name}, ...)或 MyBatis 的#{} - MyBatis 若非不得已要用
${}(如动态表名),必须配合白名单校验:查配置表确认tableName是否属于["user", "order", "product"]
容易忽略的盲区:JSON body 和 multipart/form-data
很多团队只校验 GET 参数,却放行了 POST /api/login 的 JSON body。攻击者把恶意 payload 放在 {"username":"admin'--"} 里,过滤器若没解析 JSON,就完全失效。
- 对
application/json:用ServletInputStream读原始流 →ObjectMapper.readTree()→ 递归遍历所有字符串字段做关键字匹配 - 对
multipart/form-data:不能只看getParameter(),要调用getParts()并逐个检查Part.getInputStream()(尤其是文件名、text 字段) - 日志中记录被拦截的原始请求体时,务必脱敏,避免把密码、token 也打出来
最危险的不是没加过滤器,而是加了但没覆盖 JSON、没处理 multipart、没校验白名单、也没约束 DAO 层——这种“四层防护只剩一层”的情况,在真实渗透测试中基本等于裸奔。

















