You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;")
                .replace("'", "&#x27;")
                .replace("/", "&#x2F;");
    }
}

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:35:24