关于content type‘multipart/form-data ...‘not support

在使用SpringCloud时,遇到网关转发请求到指定服务时出现Content-Type 'multipart/form-data'不被支持的错误。问题源于请求参数为multipart/form-data格式,解决方法是去除接收参数上的注解,采用SpringMVC的默认处理方式来接收表单数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目场景:

关于在使用springcloud,网关跳转指定服务显示错误信息


问题描述:

Content type 'multipart/form-data;boundary=----WebKitFormBoundaryek7Ljn5odm2QALlC;charset=UTF-8' not supported

原因分析:

这是因为请求过来的参数是content-type:multipart/form-data,是表单形式提交过来的,所以问题出现在形参上,去掉形参上的注解即可完成(只需要以springmvc的收参形式就OK了)
<think>我们正在解决SpringBoot中使用XSSFilter时,对于multipart/form-data类型请求不支持的问题。根据经验,常见的XSSFilter通常是通过ServletFilter实现的,而ServletFilter默认不会处理multipart请求,因为multipart请求需要先解析(通常使用MultipartResolver),然后才能访问参数。如果Filter在解析之前尝试读取请求体,会导致问题。解决方案通常有两种:1.调整Filter顺序,确保在MultipartFilter之后执行,或者确保在解析multipart之后执行。2.重写XSSFilter,使其能够处理multipart请求。然而,在SpringBoot中,我们通常使用CommonsMultipartResolver或StandardServletMultipartResolver来处理multipart请求。由于请求体在解析之前只能被读取一次,因此我们需要确保在解析multipart之后才进行XSS过滤。具体步骤:方案一:使用SpringMultipartFilter在SpringBoot中,我们可以配置一个MultipartFilter,并确保它在我们的XSSFilter之前执行。这样,当请求到达XSSFilter时,它已经是一个解析后的请求,我们可以安全地获取参数。1.在application.properties中启用multipart支持:spring.servlet.multipart.enabled=truespring.servlet.multipart.max-file-size=10MBspring.servlet.multipart.max-request-size=10MB2.配置MultipartFilter,并确保它在XSSFilter之前:在SpringBoot中,我们可以通过配置类来调整Filter的顺序。3.修改XSSFilter,使其能够处理普通的请求和已经解析的multipart请求(即从请求参数中获取值进行过滤)。方案二:在XSSFilter中处理multipart请求(较为复杂)如果请求是multipart/form-data类型,我们需要先解析multipart请求,然后对每个字符串类型的部分进行XSS检查。但是,这样需要自己处理multipart解析,容易出错,且性能较差。因此,推荐方案一。具体实现:步骤1:在SpringBoot中配置MultipartFilter(如果尚未配置)默认情况下,SpringBoot已经自动配置了MultipartResolver,但是为了确保请求在到达我们的Filter之前已经被解析,我们可以添加一个MultipartFilter并设置其顺序。步骤2:调整Filter顺序,使MultipartFilter在XSSFilter之前执行。步骤3:在XSSFilter中,我们不再需要直接读取请求体(因为multipart请求已经被解析),而是通过请求参数来获取值,然后进行过滤。但是,请注意:XSS过滤通常只对字符串类型的参数有效。对于文件上传部分,我们不需要进行XSS过滤(因为文件内容是二进制的)。实现示例:1.配置MultipartFilter(在SpringBoot中,我们可以通过Bean的方式添加Filter并指定顺序):```java@BeanpublicFilterRegistrationBean<MultipartFilter>multipartFilterRegistrationBean(){FilterRegistrationBean<MultipartFilter>registrationBean=newFilterRegistrationBean<>();registrationBean.setFilter(newMultipartFilter());registrationBean.setOrder(0);//设置顺序在XSSFilter之前returnregistrationBean;}```2.编写XSSFilter,注意:对于multipart请求,我们已经可以通过request.getParameter()获取参数,因此可以像处理普通请求一样处理。```javapublicclassXSSFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{//将ServletRequest转换为HttpServletRequestHttpServletRequesthttpRequest=(HttpServletRequest)request;//创建一个自定义的HttpServletRequestWrapper,用于包装请求,重写获取参数的方法,进行XSS清理XSSRequestWrapperwrappedRequest=newXSSRequestWrapper(httpRequest);chain.doFilter(wrappedRequest,response);}}```3.自定义XSSRequestWrapper,重写getParameter(),getParameterValues(),getHeader()等方法,在这些方法中对字符串进行XSS清理。```javapublicclassXSSRequestWrapperextendsHttpServletRequestWrapper{publicXSSRequestWrapper(HttpServletRequestrequest){super(request);}@OverridepublicStringgetParameter(Stringname){Stringvalue=super.getParameter(name);returncleanXSS(value);}@OverridepublicString[]getParameterValues(Stringname){String[]values=super.getParameterValues(name);if(values==null){returnnull;}intcount=values.length;String[]encodedValues=newString[count];for(inti=0;i<count;i++){encodedValues[i]=cleanXSS(values[i]);}returnencodedValues;}@OverridepublicStringgetHeader(Stringname){Stringvalue=super.getHeader(name);returncleanXSS(value);}privateStringcleanXSS(Stringvalue){if(value==null){returnnull;}//使用一些库或者自定义逻辑来清理XSS,例如使用ESAPI、Jsoup或者自己编写正则//这里只是一个示例,实际应用中应该使用更健壮的方法value=value.replaceAll("<","<").replaceAll(">",">");//更多替换规则...returnvalue;}}```4.注册XSSFilter,并设置它在MultipartFilter之后:```java@BeanpublicFilterRegistrationBean<XSSFilter>xssFilterRegistrationBean(){FilterRegistrationBean<XSSFilter>registrationBean=newFilterRegistrationBean<>();registrationBean.setFilter(newXSSFilter());registrationBean.setOrder(1);//在MultipartFilter之后registrationBean.addUrlPatterns("/*");returnregistrationBean;}```注意:上面的cleanXSS方法只是一个简单示例,实际中应该使用更健壮的XSS清理库,例如OWASPJavaHTMLSanitizer。引用说明:[^1]:在清理XSS时,我们可以使用一些成熟的库,如OWASPJavaHTMLSanitizer,或者使用如LibInjection这样的库来检测XSS攻击。但注意,我们的示例中使用了简单的替换,实际生产环境需要更强大的解决方案。另外,关于Tomcat的更新日志[^2]中提到的一些修复(例如ETag比较、日期解析等)可能与我们的问题无关,但请注意确保使用的Tomcat版本足够新,以避免已知的安全漏洞。此外,AWSIAM[^3]的相关内容与当前问题无关,无需考虑。如果按照上述步骤操作,应该能够解决multipart/form-data请求不支持的问题。因为MultipartFilter会先解析multipart请求,然后我们的XSSFilter再对解析后的参数进行过滤。但是,请注意:如果请求不是multipart类型,那么MultipartFilter不会做任何处理,所以不会影响普通请求。最后,如果问题仍然存在,请检查请求是否确实被正确解析,以及XSSFilter是否正确地包装了请求。相关问题:1.SpringBoot中如何配置MultipartResolver?2.如何自定义XSS清理逻辑以使用OWASPJavaHTMLSanitizer?3.除了Filter之外,还有哪些方法可以在SpringBoot中防御XSS攻击?4.如何测试XSSFilter是否有效?</think>### 解决 Spring Boot XSS Filter 不支持 multipart/form-data 的问题 在 Spring Boot 中使用 XSS Filter 处理 `multipart/form-data` 请求时,常见问题源于**请求解析顺序**和**数据访问方式**。以下是完整解决方案: #### 原因分析 1. **请求解析顺序问题** XSS Filter 通常通过 `HttpServletRequestWrapper` 包装请求,但 `multipart/form-data` 请求需要先由 `MultipartResolver` 解析后才能访问参数[^1]。 2. **数据访问限制** 未解析的 multipart 请求体无法直接通过 `request.getParameter()` 读取,导致 XSS Filter 失效[^2]。 3. **文件上传干扰** Filter 尝试读取二进制文件内容时可能引发 `UnsupportedOperationException`。 --- #### 解决方案 (代码实现) ##### 1. 配置 Multipart 解析器 ```java // 在启动类或配置类中添加 @Bean public MultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); } ``` ##### 2. 创建支持 Multipart 的 XSS Filter ```java public class XssFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; // 检查是否为 multipart 请求 if (isMultipartRequest(request)) { // 直接放行,由后续解析器处理 chain.doFilter(req, res); } else { // 包装普通请求 chain.doFilter(new XssRequestWrapper(request), res); } } private boolean isMultipartRequest(HttpServletRequest request) { return request.getContentType() != null && request.getContentType().startsWith("multipart/form-data"); } } ``` ##### 3. 增强的 XSS 请求包装器 ```java public class XssRequestWrapper extends HttpServletRequestWrapper { public XssRequestWrapper(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { return sanitize(super.getParameter(name)); } @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); if (values == null) return null; return Arrays.stream(values).map(this::sanitize).toArray(String[]::new); } private String sanitize(String value) { if (value == null) return null; // 使用 Jsoup 清理 HTML return Jsoup.clean(value, Whitelist.basic()); } } ``` ##### 4. 注册 Filter (确保正确顺序) ```java @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<XssFilter> xssFilter() { FilterRegistrationBean<XssFilter> reg = new FilterRegistrationBean<>(); reg.setFilter(new XssFilter()); reg.addUrlPatterns("/*"); reg.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); // 在 MultipartFilter 之后 return reg; } } ``` #### 关键配置点 1. **依赖添加** (pom.xml) ```xml <!-- Jsoup 用于 HTML 清理 --> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.15.4</version> </dependency> ``` 2. **属性配置** (application.properties) ```properties # 启用 multipart 支持 spring.servlet.multipart.enabled=true spring.servlet.multipart.max-file-size=10MB ``` 3. **Tomcat 兼容性** 确保使用 Tomcat 8.5.54+ 以获得更好的 multipart 处理能力[^2] --- #### 验证方法 1. 测试普通表单提交: ```bash curl -X POST http://localhost:8080/form \ -d "content=<script>alert(1)</script>" ``` 应返回清理后的内容:`content=alert(1)` 2. 测试文件上传: ```bash curl -X POST http://localhost:8080/upload \ -F "file=@test.jpg" \ -F "text=<script>test</script>" ``` 应正常接收文件且清理文本参数 --- #### 备选方案 如果仍遇到问题,可考虑: 1. **Controller 层清理** 在 `@PostMapping` 方法中使用 `@ModelAttribute` 绑定后手动清理: ```java @PostMapping("/upload") public String upload(@ModelAttribute @Valid FormData form, BindingResult result) { form.setText(Jsoup.clean(form.getText(), Whitelist.basic())); // ... } ``` 2. **AOP 切面处理** 对所有控制器参数进行统一清理: ```java @Aspect @Component public class XssAspect { @Before("execution(* com.example..*(..))") public void sanitizeInputs(JoinPoint joinPoint) { // 反射遍历参数并清理 } } ``` [^1]: 基于 LibInjection 的 XSS 检测原理,需在数据可访问阶段处理 [^2]: Tomcat 8.5.54+ 改进了 multipart 解析一致性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiaoYuans17

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值