在Spring Security框架中集成SQL注入防护模块,核心思路是自定义一个安全过滤器,在请求到达业务控制器之前对请求参数进行检测,识别并拦截包含SQL注入特征的请求,避免恶意SQL语句被传入数据库执行。

SQL注入防护的核心原理
SQL注入的本质是攻击者通过在请求参数中拼接恶意SQL片段,改变原有SQL语句的逻辑。防护的核心逻辑就是提取请求中的所有参数值,匹配常见的SQL注入特征,比如union_select、or_1=1、--注释符等,一旦发现匹配则直接拦截请求。
自定义SQL注入防护过滤器实现
首先需要编写一个继承OncePerRequestFilter的自定义过滤器,这个父类可以确保过滤器在一次请求中只执行一次,避免重复处理。过滤器内部需要实现参数提取和特征检测的逻辑:
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;
public class SqlInjectionFilter extends OncePerRequestFilter {
// 定义SQL注入特征的正则表达式列表
private static final List<Pattern> SQL_INJECTION_PATTERNS = new ArrayList<>();
static {
// 常见的SQL注入特征正则,可根据业务需求补充
SQL_INJECTION_PATTERNS.add(Pattern.compile("(\bunion\b|\bselect\b).*(\bfrom\b|\bwhere\b)", Pattern.CASE_INSENSITIVE));
SQL_INJECTION_PATTERNS.add(Pattern.compile("\bor\b\s*\d+\s*=\s*\d+", Pattern.CASE_INSENSITIVE));
SQL_INJECTION_PATTERNS.add(Pattern.compile("--|#|/\*.*\*/", Pattern.CASE_INSENSITIVE));
SQL_INJECTION_PATTERNS.add(Pattern.compile("\bexec\b|\bexecute\b", Pattern.CASE_INSENSITIVE));
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 包装请求,方便提取所有参数
SqlInjectionRequestWrapper requestWrapper = new SqlInjectionRequestWrapper(request);
// 检测参数是否存在SQL注入特征
if (checkSqlInjection(requestWrapper)) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("请求包含非法参数,已被拦截");
return;
}
// 无风险则放行请求
filterChain.doFilter(requestWrapper, response);
}
/**
* 检测请求参数是否包含SQL注入特征
*/
private boolean checkSqlInjection(SqlInjectionRequestWrapper request) {
// 获取所有参数名
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String paramName = parameterNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
if (paramValues != null) {
for (String paramValue : paramValues) {
if (paramValue != null && !paramValue.trim().isEmpty()) {
// 遍历所有正则匹配
for (Pattern pattern : SQL_INJECTION_PATTERNS) {
if (pattern.matcher(paramValue).find()) {
return true;
}
}
}
}
}
}
return false;
}
/**
* 自定义请求包装类,用于统一获取参数
*/
static class SqlInjectionRequestWrapper extends HttpServletRequestWrapper {
public SqlInjectionRequestWrapper(HttpServletRequest request) {
super(request);
}
}
}
将自定义过滤器整合到Spring Security
编写完过滤器后,需要将其添加到Spring Security的过滤链中,确保它在请求处理的早期阶段生效。可以在Spring Security的配置类中通过addFilterBefore方法将自定义过滤器放在默认过滤器之前:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public SqlInjectionFilter sqlInjectionFilter() {
return new SqlInjectionFilter();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
// 将自定义SQL注入过滤器添加到用户名密码认证过滤器之前
.addFilterBefore(sqlInjectionFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
注意事项与优化建议
- 正则匹配规则需要根据业务场景动态调整,避免过度拦截正常业务请求,比如某些参数可能包含
select等关键词但属于正常业务内容。 - 除了请求参数,还可以扩展检测请求头、请求路径中的内容,覆盖更多攻击入口。
- 对于检测到的恶意请求,可以记录日志便于后续安全审计,而不是直接返回简单提示。
- SQL注入防护只是数据安全的一部分,还需要结合预编译SQL、最小权限原则等措施共同保障数据库安全。
测试验证
启动应用后,可以构造包含SQL注入特征的请求进行测试,比如访问http://127.0.0.1:8080/test?param=1 or 1=1,此时请求会被过滤器拦截,返回400状态码和对应的提示信息,说明防护模块生效。
Spring_SecuritySQL注入防护自定义安全过滤器请求拦截修改时间:2026-06-27 18:42:30