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

问题描述 投票:0回答:1

如何实现 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
1个回答
0
投票

您可以从 HttpServletRequest 检查内容类型标头值,并分别应用 multipart/form-dataapplication/json 的逻辑。

if (MULTIPART_FORM_DATA_VALUE.equals(httpServletRequest.getContentType())) {

} else if (APPLICATION_JSON_VALUE.equals(httpServletRequest.getContentType())) {

}
© www.soinside.com 2019 - 2024. All rights reserved.