diff --git a/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/config/XssFilterOverrideConfig.java b/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/config/XssFilterOverrideConfig.java new file mode 100644 index 0000000..7dfcf22 --- /dev/null +++ b/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/config/XssFilterOverrideConfig.java @@ -0,0 +1,195 @@ +package org.qinan.safetyeval.adapter.config; + +import cn.hutool.core.io.IoUtil; +import com.jjb.saas.framework.core.filter.XssFilter; +import com.jjb.saas.framework.core.filter.XssHttpRequestWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ReadListener; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 框架 XssFilter / LoggingBodyFilter 会按文本处理 body,破坏 WPS 二进制上传。 + *
+ * /safetyEval-h5/**:用可重复读的 byte[] 包装请求(不改 Interceptor 类型,避免启动失败);
+ * 其它接口仍走原 XSS / LoggingBodyFilter。
+ */
+@Slf4j
+@Configuration
+public class XssFilterOverrideConfig {
+
+ private static final String H5_URI_MARKER = "/safetyEval-h5/";
+ private static final String FRAMEWORK_XSS_BEAN_NAME = "xssFilterFilterRegistrationBean";
+ private static final String LOGGING_BODY_FILTER_BEAN_NAME = "loggingBodyFilter";
+ private static final String LOGGING_BODY_FILTER_CLASS =
+ "org.minbox.framework.logging.client.filter.LoggingBodyFilter";
+
+ @Bean
+ public static BeanPostProcessor disableBinaryCorruptingFilters() {
+ return new BeanPostProcessor() {
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof FilterRegistrationBean) {
+ return processFilterRegistration((FilterRegistrationBean>) bean, beanName);
+ }
+
+ if (bean instanceof Filter
+ && (LOGGING_BODY_FILTER_BEAN_NAME.equals(beanName)
+ || LOGGING_BODY_FILTER_CLASS.equals(bean.getClass().getName()))) {
+ Filter original = (Filter) bean;
+ log.info("wrap LoggingBodyFilter beanName={}, class={}", beanName, bean.getClass().getName());
+ return new OncePerRequestFilter() {
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain chain) throws ServletException, IOException {
+ String uri = request.getRequestURI();
+ if (isH5Uri(uri)) {
+ byte[] body = IoUtil.readBytes(request.getInputStream());
+ log.info("h5 binary body cached, uri={}, size={}", uri, body.length);
+ chain.doFilter(new RepeatableByteRequestWrapper(request, body), response);
+ return;
+ }
+ original.doFilter(request, response, chain);
+ }
+ };
+ }
+
+ return bean;
+ }
+
+ private Object processFilterRegistration(FilterRegistrationBean> registration, String beanName) {
+ if (beanName.startsWith("safety")
+ || "safetyXssFilterRegistration".equals(beanName)) {
+ return registration;
+ }
+ Filter filter = null;
+ try {
+ filter = registration.getFilter();
+ } catch (Exception ignored) {
+ // ignore uninitialized registration
+ }
+ boolean match = FRAMEWORK_XSS_BEAN_NAME.equals(beanName) || filter instanceof XssFilter;
+ if (match) {
+ registration.setEnabled(false);
+ log.info("disabled framework XSS filter registration: beanName={}", beanName);
+ }
+ return registration;
+ }
+ };
+ }
+
+ @Bean
+ public FilterRegistrationBean