diff --git a/common/src/main/java/com/jeesite/common/codec/EncodeUtils.java b/common/src/main/java/com/jeesite/common/codec/EncodeUtils.java index ab0a8ba6..1e048a12 100644 --- a/common/src/main/java/com/jeesite/common/codec/EncodeUtils.java +++ b/common/src/main/java/com/jeesite/common/codec/EncodeUtils.java @@ -35,9 +35,9 @@ import java.util.regex.Pattern; * @version 2022-2-17 */ public class EncodeUtils { - + public static final String UTF_8 = "UTF-8"; - + private static final Logger logger = LoggerFactory.getLogger(EncodeUtils.class); private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); @@ -65,7 +65,7 @@ public class EncodeUtils { public static String encodeBase64(byte[] input) { return new String(Base64.encodeBase64(input)); } - + /** * Base64编码. */ @@ -97,7 +97,7 @@ public class EncodeUtils { throw ExceptionUtils.unchecked(e); } } - + /** * Base64解码. */ @@ -152,14 +152,14 @@ public class EncodeUtils { } /** - * URL 编码, Encode默认为UTF-8. + * URL 编码, Encode默认为UTF-8. */ public static String encodeUrl(String part) { return encodeUrl(part, EncodeUtils.UTF_8); } /** - * URL 编码, Encode默认为UTF-8. + * URL 编码, Encode默认为UTF-8. */ public static String encodeUrl(String part, String encoding) { if (part == null){ @@ -173,14 +173,14 @@ public class EncodeUtils { } /** - * URL 解码, Encode默认为UTF-8. + * URL 解码, Encode默认为UTF-8. */ public static String decodeUrl(String part) { return decodeUrl(part, EncodeUtils.UTF_8); } /** - * URL 解码, Encode默认为UTF-8. + * URL 解码, Encode默认为UTF-8. */ public static String decodeUrl(String part, String encoding) { if (part == null){ @@ -192,9 +192,9 @@ public class EncodeUtils { throw ExceptionUtils.unchecked(e); } } - + /** - * URL 解码(两次), Encode默认为UTF-8. + * URL 解码(两次), Encode默认为UTF-8. */ public static String decodeUrl2(String part) { return decodeUrl(decodeUrl(part)); @@ -207,7 +207,7 @@ public class EncodeUtils { Pattern.compile("\\s*on[a-z]+\\s*=\\s*(\"[^\"]+\"|'[^']+'|[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE), Pattern.compile("(eval\\((.*?)\\)|xpression\\((.*?)\\))", Pattern.CASE_INSENSITIVE), Pattern.compile("^(javascript:|vbscript:)", Pattern.CASE_INSENSITIVE) - ); + ); /** * XSS 非法字符过滤,内容以开头的用以下规则(保留标签) @@ -216,12 +216,16 @@ public class EncodeUtils { public static String xssFilter(String text) { return xssFilter(text, null); } - + /** * XSS 非法字符过滤,内容以开头的用以下规则(保留标签) * @author ThinkGem */ public static String xssFilter(String text, HttpServletRequest request) { + request = (request != null ? request : ServletUtils.getRequest()); + if (request != null && StringUtils.containsAny(request.getRequestURI(), ServletUtils.XSS_FILE_EXCLUDE_URI)) { + return text; + } String oriValue = StringUtils.trim(text); if (text != null){ String value = oriValue; @@ -232,39 +236,37 @@ public class EncodeUtils { } } // 如果开始不是HTML,XML,JOSN格式,则再进行HTML的 "、<、> 转码。 - if (!StringUtils.startsWithIgnoreCase(value, "") // HTML - && !StringUtils.startsWithIgnoreCase(value, "") // HTML + && !StringUtils.startsWithIgnoreCase(value, "': - sb.append(">"); - break; - case '<': - sb.append("<"); - break; - case '\'': - sb.append("'"); - break; - case '\"': - sb.append("""); - break; -// case '&': -// sb.append("&"); -// break; -// case '#': -// sb.append("#"); -// break; - default: - sb.append(c); - break; + case '>': + sb.append(">"); + break; + case '<': + sb.append("<"); + break; + case '\'': + sb.append("'"); + break; + case '\"': + sb.append("""); + break; +// case '&': +// sb.append("&"); +// break; +// case '#': +// sb.append("#"); +// break; + default: + sb.append(c); + break; } } value = sb.toString(); @@ -277,12 +279,12 @@ public class EncodeUtils { } return null; } - + // 预编译SQL过滤正则表达式 private static Pattern sqlPattern = Pattern.compile( "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|((extractvalue|updatexml|if|mid|database|rand|user)([\\s]*?)\\()|" - + "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|" - + "drop|execute|case when|sleep|union|load_file)\\b)", + + "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|" + + "drop|execute|case when|sleep|union|load_file)\\b)", Pattern.CASE_INSENSITIVE); private static Pattern orderByPattern = Pattern.compile("[a-z0-9_\\.\\, ]*", Pattern.CASE_INSENSITIVE); @@ -293,6 +295,7 @@ public class EncodeUtils { public static String sqlFilter(String text){ return sqlFilter(text, "common"); } + /** * SQL过滤,防止注入,传入参数输入有select相关代码,替换空。 * @author ThinkGem @@ -319,7 +322,7 @@ public class EncodeUtils { } return null; } - + // public static void main(String[] args) { // xssFilter("1 你好 我还在。"); // xssFilter("2 你好 加粗文字我还在。"); @@ -353,5 +356,5 @@ public class EncodeUtils { // sqlFilter("5 if(1=2,1,SLEEP(10)), if(mid(database(),{},1)=\\\"{}\\\",a.id,a.login_name)", "orderBy"); // sqlFilter("6 a.audit_result asc, b.audit_result2 desc, b.AuditResult3 desc", "orderBy"); // } - + } diff --git a/common/src/main/java/com/jeesite/common/web/http/ServletUtils.java b/common/src/main/java/com/jeesite/common/web/http/ServletUtils.java index 91d14f61..1494ee89 100644 --- a/common/src/main/java/com/jeesite/common/web/http/ServletUtils.java +++ b/common/src/main/java/com/jeesite/common/web/http/ServletUtils.java @@ -38,6 +38,9 @@ public class ServletUtils { private static final String[] STATIC_FILE = StringUtils.splitComma(PROPS.getProperty("web.staticFile")); private static final String[] STATIC_FILE_EXCLUDE_URI = StringUtils.splitComma(PROPS.getProperty("web.staticFileExcludeUri")); + // XSS 过滤器要排除的URI地址 + public static final String[] XSS_FILE_EXCLUDE_URI = StringUtils.splitComma(PROPS.getProperty("web.xssFilterExcludeUri")); + // AJAX 请求参数和请求头名 public static final String AJAX_PARAM_NAME = PROPS.getProperty("web.ajaxParamName", "__ajax"); public static final String AJAX_HEADER_NAME = PROPS.getProperty("web.ajaxHeaderName", "x-ajax"); @@ -125,12 +128,8 @@ public class ServletUtils { e.printStackTrace(); } } - if (STATIC_FILE_EXCLUDE_URI != null){ - for (String s : STATIC_FILE_EXCLUDE_URI){ - if (StringUtils.contains(uri, s)){ - return false; - } - } + if (StringUtils.containsAny(uri, STATIC_FILE_EXCLUDE_URI)) { + return false; } if (StringUtils.endsWithAny(uri, STATIC_FILE)){ return true; diff --git a/modules/core/src/main/resources/config/jeesite-core.yml b/modules/core/src/main/resources/config/jeesite-core.yml index 9b4be5c9..1c41f2e3 100644 --- a/modules/core/src/main/resources/config/jeesite-core.yml +++ b/modules/core/src/main/resources/config/jeesite-core.yml @@ -645,7 +645,10 @@ web: # 严格模式(更严格的数据安全验证) strictMode: false - + + # 所有请求信息将进行xss过滤,这里列出不被xss过滤的地址 + xssFilterExcludeUri: /ureport/,/visual/ + # 自定义正则表达式验证(主键、登录名) validator: id: '[a-zA-Z0-9_\-/#\u4e00-\u9fa5]{0,64}' diff --git a/web-api/src/main/resources/config/application.yml b/web-api/src/main/resources/config/application.yml index b218c6d7..06bc0af3 100644 --- a/web-api/src/main/resources/config/application.yml +++ b/web-api/src/main/resources/config/application.yml @@ -786,6 +786,9 @@ web: # # # 严格模式(更严格的数据安全验证) # strictMode: false +# +# # 所有请求信息将进行xss过滤,这里列出不被xss过滤的地址 +# xssFilterExcludeUri: /ureport/,/visual/ # # # 自定义正则表达式验证(主键、登录名) # validator: diff --git a/web/src/main/resources/config/application.yml b/web/src/main/resources/config/application.yml index f516bd41..1f98dac3 100644 --- a/web/src/main/resources/config/application.yml +++ b/web/src/main/resources/config/application.yml @@ -787,6 +787,9 @@ web: # # 严格模式(更严格的数据安全验证) # strictMode: false # +# # 所有请求信息将进行xss过滤,这里列出不被xss过滤的地址 +# xssFilterExcludeUri: /ureport/,/visual/ +# # # 自定义正则表达式验证(主键、登录名) # validator: # id: '[a-zA-Z0-9_\-/#\u4e00-\u9fa5]{0,64}'