Spring Boot 内容类型“multipart/form-data”的过滤器

Spring boot Filter for content type "multipart/form-data"

提问人:Kunaal 提问时间:11/17/2023 更新时间:11/17/2023 访问量:36

问:

如何实现 multipart/form-data 内容类型的过滤器,我为 application/json 做了它,它工作正常,但难以为 multipart/form-data 类型的请求实现它,下面是 application/json 的代码。 我是否必须为它编写不同的过滤器,或者我可以在同一个过滤器中管理它,如果有人告诉我如何以正确的方式做到这一点,我将不胜感激。

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;

@Component
public class XSSFilter implements Filter {

  @Override
  public void doFilter(
      ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
    filterChain.doFilter(
        new XSSRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
  }
}

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Safelist;

public class XSSRequestWrapper extends HttpServletRequestWrapper {
  private final String requestJsonString;
  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));

  public XSSRequestWrapper(HttpServletRequest httpServletRequest) {
    super(httpServletRequest);

    try {
      StringBuilder stringBuilder = new StringBuilder();
      bufferedReader = httpServletRequest.getReader();
      char[] charBuffer = new char[128];
      int bytesRead;
      while ((bytesRead = bufferedReader.read(charBuffer)) != -1) {
        stringBuilder.append(charBuffer, 0, bytesRead);
      }
      requestJsonString = stringBuilder.toString();
      JsonNode jsonNode = new ObjectMapper().readTree(requestJsonString);
      processJsonNode(jsonNode);
    } catch (IOException e) {
      throw new RuntimeException(e);
    } finally {
      try {
        bufferedReader.close();
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
  }

  @Override
  public ServletInputStream getInputStream() {
    return new ServletInputStreamWrapper(requestJsonString.getBytes());
  }

  @Override
  public BufferedReader getReader() {
    return new BufferedReader(new InputStreamReader(this.getInputStream()));
  }

  private void processJsonNode(JsonNode jsonNode) {
    if (jsonNode.isObject()) {
      jsonNode.fields().forEachRemaining(entry -> processJsonNode(entry.getValue()));
    } else if (jsonNode.isArray()) {
      jsonNode.elements().forEachRemaining(this::processJsonNode);
    } else {
      sanitize("key", jsonNode.asText());
    }
  }

  @Override
  public Enumeration<String> getHeaderNames() {
    Enumeration<String> headerNames = super.getHeaderNames();
    Collections.list(headerNames)
        .forEach(headerName -> sanitize(headerName, getHeader(headerName)));
    return headerNames;
  }

  @Override
  public String[] getParameterValues(String parameter) {
    String[] parameterValues = super.getParameterValues(parameter);
    Arrays.stream(parameterValues).forEach(value -> sanitize(parameter, value));
    return parameterValues;
  }

  public void sanitize(String key, String value) {
    Safelist safelist = Safelist.none();
    Document.OutputSettings outputSettings = new Document.OutputSettings().prettyPrint(false);
    if (!value.equalsIgnoreCase(Jsoup.clean(value, "", safelist, outputSettings))) {
      throw new SecurityException(
          "XSS attack error, by the key '" + key + "' and the value is '" + value + "'");
    }
  }
}

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import java.io.IOException;

public class ServletInputStreamWrapper extends ServletInputStream {

  private final byte[] data;
  private int idx = 0;

  public ServletInputStreamWrapper(byte[] data) {
    this.data = data;
  }

  @Override
  public int read() throws IOException {
    if (idx >= data.length) {
      return -1;
    }
    return data[idx++];
  }

  @Override
  public boolean isFinished() {
    return false;
  }

  @Override
  public boolean isReady() {
    return false;
  }

  @Override
  public void setReadListener(ReadListener readListener) {}
}
java spring-boot multipartform-data servlet-filters

评论


答: 暂无答案