mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 20:57:23 +08:00
feat(web/xss): XSS 增加过滤模式字段,提供清空、转义 2 种方式,默认使用清空模式
* update:完善XssProperties.mode属性为枚举类型 * feat(web/xss): xss增加过滤模式(mode)字段,提供清空(clean)/转义(escape)2种方式,默认使用clean模式
This commit is contained in:
@@ -65,14 +65,14 @@ public class XssFilter implements Filter {
|
||||
List<String> includePatterns = xssProperties.getIncludePatterns();
|
||||
if (CollectionUtil.isNotEmpty(includePatterns)) {
|
||||
if (isMatchPath(request.getServletPath(), includePatterns)) {
|
||||
filterChain.doFilter(new XssServletRequestWrapper(request), servletResponse);
|
||||
filterChain.doFilter(new XssServletRequestWrapper(request, xssProperties), servletResponse);
|
||||
} else {
|
||||
filterChain.doFilter(request, servletResponse);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 默认:执行 XSS 过滤
|
||||
filterChain.doFilter(new XssServletRequestWrapper(request), servletResponse);
|
||||
filterChain.doFilter(new XssServletRequestWrapper(request, xssProperties), servletResponse);
|
||||
return;
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
|
@@ -18,6 +18,7 @@ package top.charles7c.continew.starter.web.autoconfigure.xss;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import top.charles7c.continew.starter.core.constant.PropertiesConstants;
|
||||
import top.charles7c.continew.starter.web.enums.XssMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -50,6 +51,13 @@ public class XssProperties {
|
||||
*/
|
||||
private List<String> excludePatterns = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* xss过滤方式
|
||||
* clean : 删除xss匹配标签 (默认)
|
||||
* escape : 转义xss匹配标签
|
||||
*/
|
||||
private XssMode mode = XssMode.CLEAN;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
@@ -73,4 +81,12 @@ public class XssProperties {
|
||||
public void setExcludePatterns(List<String> excludePatterns) {
|
||||
this.excludePatterns = excludePatterns;
|
||||
}
|
||||
|
||||
public XssMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(XssMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
}
|
||||
|
@@ -16,19 +16,24 @@
|
||||
|
||||
package top.charles7c.continew.starter.web.autoconfigure.xss;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.EscapeUtil;
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
import jakarta.servlet.ReadListener;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
import top.charles7c.continew.starter.web.enums.XssMode;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 针对 XssServletRequest 进行过滤的包装类
|
||||
@@ -39,17 +44,22 @@ import java.io.StringReader;
|
||||
public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private String body = "";
|
||||
|
||||
private final static String ESCAPE_MODE = "ESCAPE";
|
||||
String[] method = {"POST", "PATCH", "PUT"};
|
||||
|
||||
public XssServletRequestWrapper(HttpServletRequest request) throws IOException {
|
||||
private final XssProperties xssProperties;
|
||||
|
||||
public XssServletRequestWrapper(HttpServletRequest request, XssProperties xssProperties) throws IOException {
|
||||
super(request);
|
||||
this.xssProperties = xssProperties;
|
||||
if (StrUtil.containsAny(request.getMethod().toUpperCase(), method)) {
|
||||
body = IoUtil.getReader(request.getReader()).readLine();
|
||||
if (StrUtil.isNotEmpty(body)) {
|
||||
body = cleanHtmlTag(body);
|
||||
if (StrUtil.isEmpty(body)) {
|
||||
return;
|
||||
}
|
||||
body = handleTag(body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,12 +74,12 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
@Override
|
||||
public String getQueryString() {
|
||||
return cleanHtmlTag(super.getQueryString());
|
||||
return handleTag(super.getQueryString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter(String name) {
|
||||
return cleanHtmlTag(super.getParameter(name));
|
||||
return handleTag(super.getParameter(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,23 +89,41 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
return values;
|
||||
}
|
||||
int length = values.length;
|
||||
String[] escapeValues = new String[length];
|
||||
String[] resultValues = new String[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
escapeValues[i] = cleanHtmlTag(values[i]);
|
||||
resultValues[i] = handleTag(values[i]);
|
||||
}
|
||||
return escapeValues;
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除文本中所有HTML标签,但是不删除标签内的内容
|
||||
* 对文本内容使用指定过滤模式
|
||||
*
|
||||
* @param content 文本内容
|
||||
* @return 处理过后的文本
|
||||
* @return 返回处理过后内容
|
||||
*/
|
||||
private String cleanHtmlTag(String content) {
|
||||
private String handleTag(String content) {
|
||||
if (StrUtil.isEmpty(content)) {
|
||||
return content;
|
||||
}
|
||||
// 获取过滤模式
|
||||
XssMode mode = xssProperties.getMode();
|
||||
//异常情况下mode为空,则默认用清空模式
|
||||
if (StrUtil.isEmpty(mode.name())) {
|
||||
return HtmlUtil.cleanHtmlTag(content);
|
||||
}
|
||||
// 如果是escape模式,则进行转义
|
||||
if (mode.name().equals(ESCAPE_MODE)) {
|
||||
List<String> reStr = ReUtil.findAllGroup0(HtmlUtil.RE_HTML_MARK, content);
|
||||
if (CollectionUtil.isEmpty(reStr)) {
|
||||
return content;
|
||||
}
|
||||
for (String s : reStr) {
|
||||
content = content.replace(s, EscapeUtil.escapeHtml4(s).replace("\\", ""));
|
||||
}
|
||||
return content;
|
||||
|
||||
}
|
||||
return HtmlUtil.cleanHtmlTag(content);
|
||||
}
|
||||
|
||||
@@ -123,4 +151,5 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.starter.web.enums;
|
||||
|
||||
/**
|
||||
* API 类型枚举
|
||||
*
|
||||
* @author whhya
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public enum XssMode {
|
||||
|
||||
/**
|
||||
* 所有 API
|
||||
*/
|
||||
CLEAN,
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
ESCAPE,
|
||||
}
|
Reference in New Issue
Block a user