如何在Spring Boot中对请求体字符转义以实现XSS防护?
实现Spring Boot的XSS请求体转义防护
看起来你已经在搭建基于Filter的XSS防护方案了,这是Spring Boot里非常常见的XSS防护手段,核心是通过包装HttpServletRequest来对请求参数、请求体里的敏感字符做转义处理。我帮你补全完整的实现代码,并说明关键细节:
1. 完整的XSSFilter实现
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class XSSFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化逻辑,比如加载自定义过滤规则,这里暂时留空 } @Override public void destroy() { // 销毁资源,这里暂时留空 } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 用自定义请求包装类替换原始请求,实现转义逻辑 chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response); } }
2. 完整的XSSRequestWrapper实现
这个包装类是核心,需要覆盖请求参数、请求体的读取方法,对敏感内容做转义:
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; public class XSSRequestWrapper extends HttpServletRequestWrapper { public XSSRequestWrapper(HttpServletRequest request) { super(request); } // 处理单个请求参数 @Override public String getParameter(String name) { String value = super.getParameter(name); return value != null ? escapeXSS(value) : null; } // 处理多值请求参数(比如复选框) @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); if (values == null) { return null; } String[] escapedValues = new String[values.length]; for (int i = 0; i < values.length; i++) { escapedValues[i] = escapeXSS(values[i]); } return escapedValues; } // 处理请求参数Map @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> originalMap = super.getParameterMap(); Map<String, String[]> escapedMap = new HashMap<>(); for (Map.Entry<String, String[]> entry : originalMap.entrySet()) { String[] values = entry.getValue(); String[] escapedValues = new String[values.length]; for (int i = 0; i < values.length; i++) { escapedValues[i] = escapeXSS(values[i]); } escapedMap.put(entry.getKey(), escapedValues); } return escapedMap; } // 处理JSON格式的请求体 @Override public BufferedReader getReader() throws IOException { String requestBody = readRequestBody(super.getInputStream()); String escapedBody = escapeXSS(requestBody); return new BufferedReader(new InputStreamReader( new ByteArrayInputStream(escapedBody.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8 )); } // 读取原始请求体内容 private String readRequestBody(java.io.InputStream inputStream) throws IOException { StringBuilder stringBuilder = new StringBuilder(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); char[] charBuffer = new char[128]; int bytesRead; while ((bytesRead = bufferedReader.read(charBuffer)) != -1) { stringBuilder.append(charBuffer, 0, bytesRead); } return stringBuilder.toString(); } // 核心XSS转义方法,替换敏感HTML字符为实体 private String escapeXSS(String value) { if (value == null) { return null; } return value .replace("&", "&") .replace("<", "<") .replace(">", ">") .replace("\"", """) .replace("'", "'") .replace("/", "/"); } }
3. 在Spring Boot中注册XSSFilter
有两种常用方式注册这个Filter:
方式一:使用@WebFilter注解
在XSSFilter类上添加注解:
import javax.servlet.annotation.WebFilter; @WebFilter(urlPatterns = "/*") // 对所有请求生效 public class XSSFilter implements Filter { // ... 原有代码 }
然后在Spring Boot启动类上添加@ServletComponentScan,让Spring扫描到这个Filter:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; @SpringBootApplication @ServletComponentScan public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
方式二:通过配置类手动注册
创建一个配置类,手动配置Filter的拦截规则和执行顺序:
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<XSSFilter> xssFilterRegistrationBean() { FilterRegistrationBean<XSSFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new XSSFilter()); registrationBean.addUrlPatterns("/*"); // 拦截所有请求 registrationBean.setOrder(1); // 数字越小,Filter执行优先级越高 return registrationBean; } }
关键注意事项
- 转义逻辑扩展:如果需要更强的防护,可以在
escapeXSS方法中添加更多敏感字符的替换规则,比如处理JavaScript伪协议、事件绑定等。 - 二进制请求兼容:如果你的应用涉及文件上传或二进制请求体,需要在Filter中添加判断逻辑,避免对二进制内容做转义,否则会破坏文件完整性。
- 请求体重复读取:如果你的应用中有其他Filter需要读取请求体,可能需要额外处理请求体的重复读取问题(比如将请求体缓存起来)。
内容的提问来源于stack exchange,提问作者renanleandrof
相关产品推荐
相关产品推荐

