You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在过滤器中读取Multipart请求且不消耗请求本身以实现XSS防护?

解决遗留应用Multipart-FormData请求的XSS防护问题

太懂这种遗留系统踩坑的痛苦了!之前的请求包装器只能处理urlencoded表单,碰到multipart就失效,试过的方案要么不兼容现有功能,要么直接把请求搞废。结合你的场景,这里有几个能在不消耗请求的前提下实现XSS防护的思路:

方案1:基于Servlet 3.0+ Part API做缓存式请求包装

Servlet 3.0及以上版本自带的Part API是处理multipart请求的标准方式,我们可以做一个带缓存的HttpServletRequestWrapper,提前把所有请求内容读出来清理并缓存,后续应用拿参数时直接从缓存取,不会碰原始请求流。

具体步骤:

  • 写一个MultipartXssSafeRequestWrapper继承HttpServletRequestWrapper
  • 在构造方法里先判断是否是multipart请求:request.getContentType() != null && request.getContentType().startsWith("multipart/form-data")
  • 如果是,调用request.getParts()遍历所有Part:
    • 对于文本类型的Part(通过part.getContentType()判断,或者识别表单字段),读取它的内容,用你现有的XSS清理逻辑处理后,存入一个Map<String, List<String>>缓存起来
    • 对于文件类型的Part,直接把Part对象缓存到集合里,不修改文件内容
  • 重写getParametergetParameterValuesgetParameterMap这些方法,优先返回缓存里的清理后值
  • 重写getPartgetParts方法,返回缓存的Part(文本Part确保返回清理后的内容,文件Part直接返回原对象)

这个方案的好处是完全兼容Servlet标准,不需要额外依赖,也不会破坏现有的Angular文件上传功能——因为文件Part是原样缓存的,后续应用读取文件流不受影响。

方案2:扩展Commons FileUpload的工厂类做源头清理

如果你之前项目里用了Commons FileUpload,可以自定义一个FileItemFactory,在生成FileItem的时候就把文本参数清理好,同时缓存所有解析后的内容,避免重复读取请求流。

怎么做:

  • 继承DiskFileItemFactory,重写createItem方法
  • 当创建的是文本字段的FileItem时,先读取它的内容,用你的XSS逻辑清理后再存回去;如果是文件字段,直接返回原FileItem
  • 在过滤器里,用这个自定义工厂类来解析multipart请求,把解析后的文本参数存入缓存,然后让请求包装器的参数获取方法返回这些清理后的值
  • 关键是要把解析后的FileItem集合缓存起来,后续应用需要获取文件时,直接从缓存里拿,不会再去读原始请求流

这个方案适合已经依赖Commons FileUpload的项目,复用现有解析逻辑,改动量比较小。

方案3:容器级配置+请求包装器的兼容方案

如果你的容器是Tomcat,不想改太多代码,可以试试调整容器的multipart配置,但避开allowCasualMultipartParsing=true这个坑:

  • web.xml里给需要处理multipart的Servlet添加<multipart-config>配置(指定临时文件路径、大小限制等)
  • 然后在请求包装器里,对于multipart请求,通过Servlet的getParts()方法读取参数并清理,缓存后返回

这个方案要注意不同容器的multipart配置差异,比如Jetty和Tomcat的配置略有不同,但核心都是用容器的标准API来读取,避免自己解析导致请求流被消耗。

必须避的坑

  • 绝对不要直接读请求流然后不重置!一定要把读取后的内容缓存成字节数组,并重写getInputStreamgetReader方法返回缓存的流,否则后续应用会读不到请求内容
  • 文件Part只需要清理文件名(如果有XSS风险的话),不要修改文件的二进制内容,不然上传的文件会损坏
  • 复用你之前已经验证过的XSS清理逻辑,不要随便换规则,确保urlencoded和multipart请求的防护标准一致

应该能解决你的问题了,祝你早日搞定这个棘手的bug!

内容的提问来源于stack exchange,提问作者CSoft

火山引擎 最新活动