bean = new FilterRegistrationBean<>(filter);
bean.setOrder(order);
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java
new file mode 100644
index 000000000..5a72834af
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.framework.web.core.clean;
+
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.safety.Safelist;
+
+public class JsoupXssCleaner implements XssCleaner {
+
+ private final Safelist safelist;
+
+ /**
+ * 用于在 src 属性使用相对路径时,强制转换为绝对路径。 为空时不处理,值应为绝对路径的前缀(包含协议部分)
+ */
+ private final String baseUri;
+
+ /**
+ * 无参构造,默认使用 {@link JsoupXssCleaner#buildSafelist} 方法构建一个安全列表
+ */
+ public JsoupXssCleaner() {
+ this.safelist = buildSafelist();
+ this.baseUri = "";
+ }
+
+ public JsoupXssCleaner(Safelist safelist) {
+ this.safelist = safelist;
+ this.baseUri = "";
+ }
+
+ public JsoupXssCleaner(String baseUri) {
+ this.safelist = buildSafelist();
+ this.baseUri = baseUri;
+ }
+
+ public JsoupXssCleaner(Safelist safelist, String baseUri) {
+ this.safelist = safelist;
+ this.baseUri = baseUri;
+ }
+
+ /**
+ *
+ * 构建一个 Xss 清理的 Safelist 规则。
+ *
+ *
+ *
+ * 基于 Safelist#relaxed() 的基础上:
+ * - 扩展支持了 style 和 class 属性
+ * - a 标签额外支持了 target 属性
+ * - img 标签额外支持了 data 协议,便于支持 base64
+ *
+ * @return Safelist
+ */
+ protected Safelist buildSafelist() {
+ // 使用 jsoup 提供的默认的
+ Safelist relaxedSafelist = Safelist.relaxed();
+ // 富文本编辑时一些样式是使用 style 来进行实现的
+ // 比如红色字体 style="color:red;", 所以需要给所有标签添加 style 属性
+ // 注意:style 属性会有注入风险
+ relaxedSafelist.addAttributes(":all", "style", "class");
+ // 保留 a 标签的 target 属性
+ relaxedSafelist.addAttributes("a", "target");
+ // 支持img 为base64
+ relaxedSafelist.addProtocols("img", "src", "data");
+
+ // 保留相对路径, 保留相对路径时,必须提供对应的 baseUri 属性,否则依然会被删除
+ // WHITELIST.preserveRelativeLinks(false);
+
+ // 移除 a 标签和 img 标签的一些协议限制,这会导致 xss 防注入失效,如
+ // 虽然可以重写 WhiteList#isSafeAttribute 来处理,但是有隐患,所以暂时不支持相对路径
+ // WHITELIST.removeProtocols("a", "href", "ftp", "http", "https", "mailto");
+ // WHITELIST.removeProtocols("img", "src", "http", "https");
+
+ return relaxedSafelist;
+ }
+
+ @Override
+ public String clean(String html) {
+ return Jsoup.clean(html, baseUri, safelist, new Document.OutputSettings().prettyPrint(false));
+ }
+
+}
+
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java
new file mode 100644
index 000000000..a5ecc1bcc
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java
@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.framework.web.core.clean;
+
+/**
+ * 对 html 文本中的有 Xss 风险的数据进行清理
+ */
+public interface XssCleaner {
+ /**
+ * 清理有 Xss 风险的文本
+ *
+ * @param html 原 html
+ * @return 清理后的 html
+ */
+ String clean(String html);
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java
index 050a86cc1..2da18768d 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.framework.web.core.filter;
import cn.iocoder.yudao.framework.web.config.XssProperties;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
import lombok.AllArgsConstructor;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -13,7 +14,7 @@ import java.io.IOException;
/**
* Xss 过滤器
- *
+ *
* 对 Xss 不了解的胖友,可以看看 http://www.iocoder.cn/Fight/The-new-girl-asked-me-why-AJAX-requests-are-not-secure-I-did-not-answer/
*
* @author 芋道源码
@@ -30,10 +31,12 @@ public class XssFilter extends OncePerRequestFilter {
*/
private final PathMatcher pathMatcher;
+ private final XssCleaner xssCleaner;
+
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
- filterChain.doFilter(new XssRequestWrapper(request), response);
+ filterChain.doFilter(new XssRequestWrapper(request, xssCleaner), response);
}
@Override
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
index 25bd20978..1724cb163 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
@@ -1,21 +1,10 @@
package cn.iocoder.yudao.framework.web.core.filter;
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ReflectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HTMLFilter;
-import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
+import java.util.LinkedHashMap;
import java.util.Map;
/**
@@ -24,113 +13,75 @@ import java.util.Map;
* @author 芋道源码
*/
public class XssRequestWrapper extends HttpServletRequestWrapper {
+ private final XssCleaner xssCleaner;
- /**
- * 基于线程级别的 HTMLFilter 对象,因为它线程非安全
- */
- private static final ThreadLocal HTML_FILTER = ThreadLocal.withInitial(() -> {
- HTMLFilter htmlFilter = new HTMLFilter();
- // 反射修改 encodeQuotes 属性为 false,避免 " 被转移成 " 字符
- ReflectUtil.setFieldValue(htmlFilter, "encodeQuotes", false);
- return htmlFilter;
- });
-
- public XssRequestWrapper(HttpServletRequest request) {
+ public XssRequestWrapper(HttpServletRequest request, XssCleaner xssCleaner) {
super(request);
+ this.xssCleaner = xssCleaner;
}
- private static String filterXss(String content) {
- if (StrUtil.isEmpty(content)) {
- return content;
+ @Override
+ public Map getParameterMap() {
+ Map map = new LinkedHashMap<>();
+ Map parameters = super.getParameterMap();
+ for (Map.Entry entry : parameters.entrySet()) {
+ String[] values = entry.getValue();
+ for (int i = 0; i < values.length; i++) {
+ values[i] = xssCleaner.clean(values[i]);
+ }
+ map.put(entry.getKey(), values);
}
- return HTML_FILTER.get().filter(content);
- }
-
- // ========== IO 流相关 ==========
-
- @Override
- public BufferedReader getReader() throws IOException {
- return new BufferedReader(new InputStreamReader(this.getInputStream()));
- }
-
- @Override
- public ServletInputStream getInputStream() throws IOException {
- // 如果非 json 请求,不进行 Xss 处理
- if (!ServletUtils.isJsonRequest(this)) {
- return super.getInputStream();
- }
-
- // 读取内容,并过滤
- String content = IoUtil.readUtf8(super.getInputStream());
- content = filterXss(content);
- final ByteArrayInputStream newInputStream = new ByteArrayInputStream(content.getBytes());
- // 返回 ServletInputStream
- return new ServletInputStream() {
-
- @Override
- public int read() {
- return newInputStream.read();
- }
-
- @Override
- public boolean isFinished() {
- return true;
- }
-
- @Override
- public boolean isReady() {
- return true;
- }
-
- @Override
- public void setReadListener(ReadListener readListener) {}
-
- };
- }
-
- // ========== Param 相关 ==========
-
- @Override
- public String getParameter(String name) {
- String value = super.getParameter(name);
- return filterXss(value);
+ return map;
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
- if (ArrayUtil.isEmpty(values)) {
- return values;
+ if (values == null) {
+ return null;
}
- // 过滤处理
- for (int i = 0; i < values.length; i++) {
- values[i] = filterXss(values[i]);
+ int count = values.length;
+ String[] encodedValues = new String[count];
+ for (int i = 0; i < count; i++) {
+ encodedValues[i] = xssCleaner.clean(values[i]);
}
- return values;
+ return encodedValues;
}
@Override
- public Map getParameterMap() {
- Map valueMap = super.getParameterMap();
- if (CollUtil.isEmpty(valueMap)) {
- return valueMap;
+ public String getParameter(String name) {
+ String value = super.getParameter(name);
+ if (value == null) {
+ return null;
}
- // 过滤处理
- for (Map.Entry entry : valueMap.entrySet()) {
- String[] values = entry.getValue();
- for (int i = 0; i < values.length; i++) {
- values[i] = filterXss(values[i]);
- }
- }
- return valueMap;
+ return xssCleaner.clean(value);
}
- // ========== Header 相关 ==========
+ @Override
+ public Object getAttribute(String name) {
+ Object value = super.getAttribute(name);
+ if (value instanceof String) {
+ xssCleaner.clean((String) value);
+ }
+ return value;
+ }
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
- return filterXss(value);
+ if (value == null) {
+ return null;
+ }
+ return xssCleaner.clean(value);
+ }
+
+ @Override
+ public String getQueryString() {
+ String value = super.getQueryString();
+ if (value == null) {
+ return null;
+ }
+ return xssCleaner.clean(value);
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java
new file mode 100644
index 000000000..185469be5
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java
@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.framework.web.core.json;
+
+import cn.iocoder.yudao.framework.web.config.XssProperties;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+
+/**
+ * XSS过滤 jackson 反序列化器
+ *
+ * 参考 ballcat 实现
+ */
+@Slf4j
+@AllArgsConstructor
+public class XssStringJsonDeserializer extends StringDeserializer {
+
+ private final XssCleaner xssCleaner;
+ private final XssProperties xssProperties;
+
+ @Override
+ public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ if (p.hasToken(JsonToken.VALUE_STRING)) {
+ return getCleanText(p.getText());
+ }
+ JsonToken t = p.currentToken();
+ // [databind#381]
+ if (t == JsonToken.START_ARRAY) {
+ return _deserializeFromArray(p, ctxt);
+ }
+ // need to gracefully handle byte[] data, as base64
+ if (t == JsonToken.VALUE_EMBEDDED_OBJECT) {
+ Object ob = p.getEmbeddedObject();
+ if (ob == null) {
+ return null;
+ }
+ if (ob instanceof byte[]) {
+ return ctxt.getBase64Variant().encode((byte[]) ob, false);
+ }
+ // otherwise, try conversion using toString()...
+ return ob.toString();
+ }
+ // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
+ if (t == JsonToken.START_OBJECT) {
+ return ctxt.extractScalarFromObject(p, this, _valueClass);
+ }
+ // allow coercions for other scalar types
+ // 17-Jan-2018, tatu: Related to [databind#1853] avoid FIELD_NAME by ensuring it's
+ // "real" scalar
+ if (t.isScalarValue()) {
+ String text = p.getValueAsString();
+ return getCleanText(text);
+ }
+ return (String) ctxt.handleUnexpectedToken(_valueClass, p);
+ }
+
+ private String getCleanText(String text) {
+ if (text == null) {
+ return null;
+ }
+ return xssProperties.isEnable() ? xssCleaner.clean(text) : text;
+ }
+
+}
+
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonSerializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonSerializer.java
new file mode 100644
index 000000000..261c99ffe
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonSerializer.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.framework.web.core.json;
+
+import cn.iocoder.yudao.framework.web.config.XssProperties;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import lombok.AllArgsConstructor;
+
+import java.io.IOException;
+
+/**
+ * XSS过滤 jackson 序列化器
+ *
+ * 参考 ballcat 实现
+ */
+@AllArgsConstructor
+public class XssStringJsonSerializer extends JsonSerializer {
+
+ private final XssCleaner xssCleaner;
+ private final XssProperties xssProperties;
+
+
+ @Override
+ public Class handledType() {
+ return String.class;
+ }
+
+ @Override
+ public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
+ throws IOException {
+ if (value != null) {
+ // 开启 Xss 才进行处理
+ if (xssProperties.isEnable()) {
+ value = xssCleaner.clean(value);
+ }
+ jsonGenerator.writeString(value);
+ }
+ }
+
+}
+
From 099754c26e9f1e0e460ddefd25609a73625d157f Mon Sep 17 00:00:00 2001
From: gaibu <1016771049@qq.com>
Date: Tue, 10 Jan 2023 19:27:24 +0800
Subject: [PATCH 2/2] =?UTF-8?q?fix:=20xss=20=E5=90=AF=E7=94=A8=E5=90=8E?=
=?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E4=B8=8A=E4=BC=A0=E5=9B=BE=E7=89=87?=
=?UTF-8?q?=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yudao-dependencies/pom.xml | 11 ++---
yudao-framework/yudao-common/pom.xml | 4 --
.../yudao-spring-boot-starter-web/pom.xml | 5 +++
.../web/config/YudaoWebAutoConfiguration.java | 8 ++--
.../web/core/clean/JsoupXssCleaner.java | 17 ++++----
.../framework/web/core/clean/XssCleaner.java | 1 +
.../web/core/filter/XssRequestWrapper.java | 4 ++
.../core/json/XssStringJsonDeserializer.java | 23 +++-------
.../core/json/XssStringJsonSerializer.java | 42 -------------------
9 files changed, 34 insertions(+), 81 deletions(-)
delete mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonSerializer.java
diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index cc23f245c..22cb6da5c 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -395,11 +395,6 @@
-
- org.jsoup
- jsoup
- ${jsoup.version}
-
cn.iocoder.boot
yudao-common
@@ -528,6 +523,12 @@
${ip2region.version}
+
+ org.jsoup
+ jsoup
+ ${jsoup.version}
+
+
com.squareup.okio
diff --git a/yudao-framework/yudao-common/pom.xml b/yudao-framework/yudao-common/pom.xml
index a732967f2..2ad12ad87 100644
--- a/yudao-framework/yudao-common/pom.xml
+++ b/yudao-framework/yudao-common/pom.xml
@@ -133,10 +133,6 @@
transmittable-thread-local
-
- org.jsoup
- jsoup
-
diff --git a/yudao-framework/yudao-spring-boot-starter-web/pom.xml b/yudao-framework/yudao-spring-boot-starter-web/pom.xml
index 8662584e3..7d277790c 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-web/pom.xml
@@ -67,6 +67,11 @@
provided
+
+
+ org.jsoup
+ jsoup
+
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
index 50586d4a6..95955d5ee 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
@@ -131,8 +131,8 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
*
* @return XssCleaner
*/
- @ConditionalOnMissingBean(XssCleaner.class)
@Bean
+ @ConditionalOnMissingBean(XssCleaner.class)
public XssCleaner xssCleaner() {
return new JsoupXssCleaner();
}
@@ -145,12 +145,12 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
@Bean
@ConditionalOnMissingBean(name = "xssJacksonCustomizer")
@ConditionalOnBean(ObjectMapper.class)
- public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(XssCleaner xssCleaner, XssProperties xssProperties) {
+ @ConditionalOnProperty(value = "yudao.xss.enable", havingValue = "true")
+ public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(XssCleaner xssCleaner) {
// 在反序列化时进行 xss 过滤,可以替换使用 XssStringJsonSerializer,在序列化时进行处理
- return builder -> builder.deserializerByType(String.class, new XssStringJsonDeserializer(xssCleaner, xssProperties));
+ return builder -> builder.deserializerByType(String.class, new XssStringJsonDeserializer(xssCleaner));
}
-
private static FilterRegistrationBean createFilterBean(T filter, Integer order) {
FilterRegistrationBean bean = new FilterRegistrationBean<>(filter);
bean.setOrder(order);
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java
index 5a72834af..559267c3f 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java
@@ -4,6 +4,9 @@ import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Safelist;
+/**
+ * jsonp 过滤字符串
+ */
public class JsoupXssCleaner implements XssCleaner {
private final Safelist safelist;
@@ -37,19 +40,15 @@ public class JsoupXssCleaner implements XssCleaner {
}
/**
- *
* 构建一个 Xss 清理的 Safelist 规则。
- *
- *
- *
* 基于 Safelist#relaxed() 的基础上:
- * - 扩展支持了 style 和 class 属性
- * - a 标签额外支持了 target 属性
- * - img 标签额外支持了 data 协议,便于支持 base64
- *
+ * 1. 扩展支持了 style 和 class 属性
+ * 2. a 标签额外支持了 target 属性
+ * 3. img 标签额外支持了 data 协议,便于支持 base64
+ *
* @return Safelist
*/
- protected Safelist buildSafelist() {
+ private Safelist buildSafelist() {
// 使用 jsoup 提供的默认的
Safelist relaxedSafelist = Safelist.relaxed();
// 富文本编辑时一些样式是使用 style 来进行实现的
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java
index a5ecc1bcc..433f7e775 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java
@@ -4,6 +4,7 @@ package cn.iocoder.yudao.framework.web.core.clean;
* 对 html 文本中的有 Xss 风险的数据进行清理
*/
public interface XssCleaner {
+
/**
* 清理有 Xss 风险的文本
*
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
index 1724cb163..7beed46cc 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
@@ -20,6 +20,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
this.xssCleaner = xssCleaner;
}
+ // ============================ parameter ============================
@Override
public Map getParameterMap() {
Map map = new LinkedHashMap<>();
@@ -57,6 +58,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
return xssCleaner.clean(value);
}
+ // ============================ attribute ============================
@Override
public Object getAttribute(String name) {
Object value = super.getAttribute(name);
@@ -66,6 +68,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
return value;
}
+ // ============================ header ============================
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
@@ -75,6 +78,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
return xssCleaner.clean(value);
}
+ // ============================ queryString ============================
@Override
public String getQueryString() {
String value = super.getQueryString();
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java
index 185469be5..7e1f631c7 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.framework.web.core.json;
-import cn.iocoder.yudao.framework.web.config.XssProperties;
import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
@@ -12,21 +11,21 @@ import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
- * XSS过滤 jackson 反序列化器
+ * XSS 过滤 jackson 反序列化器。
+ * 在反序列化的过程中,会对字符串进行 XSS 过滤。
*
- * 参考 ballcat 实现
+ * @author Hccake
*/
@Slf4j
@AllArgsConstructor
public class XssStringJsonDeserializer extends StringDeserializer {
private final XssCleaner xssCleaner;
- private final XssProperties xssProperties;
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.hasToken(JsonToken.VALUE_STRING)) {
- return getCleanText(p.getText());
+ return xssCleaner.clean(p.getText());
}
JsonToken t = p.currentToken();
// [databind#381]
@@ -49,22 +48,12 @@ public class XssStringJsonDeserializer extends StringDeserializer {
if (t == JsonToken.START_OBJECT) {
return ctxt.extractScalarFromObject(p, this, _valueClass);
}
- // allow coercions for other scalar types
- // 17-Jan-2018, tatu: Related to [databind#1853] avoid FIELD_NAME by ensuring it's
- // "real" scalar
+
if (t.isScalarValue()) {
String text = p.getValueAsString();
- return getCleanText(text);
+ return xssCleaner.clean(text);
}
return (String) ctxt.handleUnexpectedToken(_valueClass, p);
}
-
- private String getCleanText(String text) {
- if (text == null) {
- return null;
- }
- return xssProperties.isEnable() ? xssCleaner.clean(text) : text;
- }
-
}
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonSerializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonSerializer.java
deleted file mode 100644
index 261c99ffe..000000000
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonSerializer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package cn.iocoder.yudao.framework.web.core.json;
-
-import cn.iocoder.yudao.framework.web.config.XssProperties;
-import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import lombok.AllArgsConstructor;
-
-import java.io.IOException;
-
-/**
- * XSS过滤 jackson 序列化器
- *
- * 参考 ballcat 实现
- */
-@AllArgsConstructor
-public class XssStringJsonSerializer extends JsonSerializer {
-
- private final XssCleaner xssCleaner;
- private final XssProperties xssProperties;
-
-
- @Override
- public Class handledType() {
- return String.class;
- }
-
- @Override
- public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
- throws IOException {
- if (value != null) {
- // 开启 Xss 才进行处理
- if (xssProperties.isEnable()) {
- value = xssCleaner.clean(value);
- }
- jsonGenerator.writeString(value);
- }
- }
-
-}
-