mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-10 20:57:18 +08:00
refactor(web/xss): 优化 XSS 过滤部分代码
This commit is contained in:
@@ -55,7 +55,7 @@ public class XssFilter implements Filter {
|
|||||||
FilterChain filterChain) throws IOException, ServletException {
|
FilterChain filterChain) throws IOException, ServletException {
|
||||||
// 未开启 XSS 过滤,则直接跳过
|
// 未开启 XSS 过滤,则直接跳过
|
||||||
if (servletRequest instanceof HttpServletRequest request && xssProperties.isEnabled()) {
|
if (servletRequest instanceof HttpServletRequest request && xssProperties.isEnabled()) {
|
||||||
// 放行路由:忽略 XSS 过滤()
|
// 放行路由:忽略 XSS 过滤
|
||||||
List<String> excludePatterns = xssProperties.getExcludePatterns();
|
List<String> excludePatterns = xssProperties.getExcludePatterns();
|
||||||
if (CollectionUtil.isNotEmpty(excludePatterns) && isMatchPath(request.getServletPath(), excludePatterns)) {
|
if (CollectionUtil.isNotEmpty(excludePatterns) && isMatchPath(request.getServletPath(), excludePatterns)) {
|
||||||
filterChain.doFilter(request, servletResponse);
|
filterChain.doFilter(request, servletResponse);
|
||||||
|
@@ -52,9 +52,7 @@ public class XssProperties {
|
|||||||
private List<String> excludePatterns = new ArrayList<>();
|
private List<String> excludePatterns = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xss过滤方式
|
* XSS 模式
|
||||||
* clean : 删除xss匹配标签 (默认)
|
|
||||||
* escape : 转义xss匹配标签
|
|
||||||
*/
|
*/
|
||||||
private XssMode mode = XssMode.CLEAN;
|
private XssMode mode = XssMode.CLEAN;
|
||||||
|
|
||||||
|
@@ -18,15 +18,14 @@ package top.continew.starter.web.autoconfigure.xss;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.*;
|
||||||
import cn.hutool.core.util.EscapeUtil;
|
|
||||||
import cn.hutool.core.util.ReUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.http.HtmlUtil;
|
import cn.hutool.http.HtmlUtil;
|
||||||
|
import cn.hutool.http.Method;
|
||||||
import jakarta.servlet.ReadListener;
|
import jakarta.servlet.ReadListener;
|
||||||
import jakarta.servlet.ServletInputStream;
|
import jakarta.servlet.ServletInputStream;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||||
|
import top.continew.starter.core.constant.StringConstants;
|
||||||
import top.continew.starter.web.enums.XssMode;
|
import top.continew.starter.web.enums.XssMode;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -38,27 +37,25 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* 针对 XssServletRequest 进行过滤的包装类
|
* 针对 XssServletRequest 进行过滤的包装类
|
||||||
*
|
*
|
||||||
* @author whh
|
* @author whhya
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
private String body = "";
|
|
||||||
|
|
||||||
private final static String ESCAPE_MODE = "ESCAPE";
|
|
||||||
String[] method = {"POST", "PATCH", "PUT"};
|
|
||||||
|
|
||||||
private final XssProperties xssProperties;
|
private final XssProperties xssProperties;
|
||||||
|
|
||||||
|
private String body = "";
|
||||||
|
|
||||||
public XssServletRequestWrapper(HttpServletRequest request, XssProperties xssProperties) throws IOException {
|
public XssServletRequestWrapper(HttpServletRequest request, XssProperties xssProperties) throws IOException {
|
||||||
super(request);
|
super(request);
|
||||||
this.xssProperties = xssProperties;
|
this.xssProperties = xssProperties;
|
||||||
if (StrUtil.containsAny(request.getMethod().toUpperCase(), method)) {
|
if (StrUtil.containsAny(request.getMethod().toUpperCase(), Method.POST.name(), Method.PATCH.name(), Method.PUT
|
||||||
|
.name())) {
|
||||||
body = IoUtil.getReader(request.getReader()).readLine();
|
body = IoUtil.getReader(request.getReader()).readLine();
|
||||||
if (StrUtil.isEmpty(body)) {
|
if (StrUtil.isEmpty(body)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
body = handleTag(body);
|
body = this.handleTag(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,12 +71,12 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getQueryString() {
|
public String getQueryString() {
|
||||||
return handleTag(super.getQueryString());
|
return this.handleTag(super.getQueryString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getParameter(String name) {
|
public String getParameter(String name) {
|
||||||
return handleTag(super.getParameter(name));
|
return this.handleTag(super.getParameter(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,13 +88,13 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
int length = values.length;
|
int length = values.length;
|
||||||
String[] resultValues = new String[length];
|
String[] resultValues = new String[length];
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
resultValues[i] = handleTag(values[i]);
|
resultValues[i] = this.handleTag(values[i]);
|
||||||
}
|
}
|
||||||
return resultValues;
|
return resultValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对文本内容使用指定过滤模式
|
* 对文本内容进行 XSS 处理
|
||||||
*
|
*
|
||||||
* @param content 文本内容
|
* @param content 文本内容
|
||||||
* @return 返回处理过后内容
|
* @return 返回处理过后内容
|
||||||
@@ -106,24 +103,20 @@ public class XssServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
if (StrUtil.isEmpty(content)) {
|
if (StrUtil.isEmpty(content)) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
// 获取过滤模式
|
|
||||||
XssMode mode = xssProperties.getMode();
|
XssMode mode = xssProperties.getMode();
|
||||||
//异常情况下mode为空,则默认用清空模式
|
// 转义
|
||||||
if (StrUtil.isEmpty(mode.name())) {
|
if (XssMode.ESCAPE.equals(mode)) {
|
||||||
return HtmlUtil.cleanHtmlTag(content);
|
|
||||||
}
|
|
||||||
// 如果是escape模式,则进行转义
|
|
||||||
if (mode.name().equals(ESCAPE_MODE)) {
|
|
||||||
List<String> reStr = ReUtil.findAllGroup0(HtmlUtil.RE_HTML_MARK, content);
|
List<String> reStr = ReUtil.findAllGroup0(HtmlUtil.RE_HTML_MARK, content);
|
||||||
if (CollectionUtil.isEmpty(reStr)) {
|
if (CollectionUtil.isEmpty(reStr)) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
for (String s : reStr) {
|
for (String s : reStr) {
|
||||||
content = content.replace(s, EscapeUtil.escapeHtml4(s).replace("\\", ""));
|
content = content.replace(s, EscapeUtil.escapeHtml4(s)
|
||||||
|
.replace(StringConstants.BACKSLASH, StringConstants.EMPTY));
|
||||||
}
|
}
|
||||||
return content;
|
return content;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// 清理
|
||||||
return HtmlUtil.cleanHtmlTag(content);
|
return HtmlUtil.cleanHtmlTag(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
package top.continew.starter.web.enums;
|
package top.continew.starter.web.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 类型枚举
|
* XSS 模式枚举
|
||||||
*
|
*
|
||||||
* @author whhya
|
* @author whhya
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
@@ -25,11 +25,12 @@ package top.continew.starter.web.enums;
|
|||||||
public enum XssMode {
|
public enum XssMode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有 API
|
* 清理
|
||||||
*/
|
*/
|
||||||
CLEAN,
|
CLEAN,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页
|
* 转义
|
||||||
*/
|
*/
|
||||||
ESCAPE,
|
ESCAPE,
|
||||||
}
|
}
|
Reference in New Issue
Block a user