作者 RuoYi

优化XSS跨站脚本过滤

@@ -115,6 +115,6 @@ xss: @@ -115,6 +115,6 @@ xss:
115 # 过滤开关 115 # 过滤开关
116 enabled: true 116 enabled: true
117 # 排除链接(多个用逗号分隔) 117 # 排除链接(多个用逗号分隔)
118 - excludes: /system/notice/* 118 + excludes: /system/notice
119 # 匹配链接 119 # 匹配链接
120 urlPatterns: /system/*,/monitor/*,/tool/* 120 urlPatterns: /system/*,/monitor/*,/tool/*
@@ -201,7 +201,7 @@ public class SysUser extends BaseEntity @@ -201,7 +201,7 @@ public class SysUser extends BaseEntity
201 this.avatar = avatar; 201 this.avatar = avatar;
202 } 202 }
203 203
204 - @JsonIgnore 204 + @JsonIgnore
205 @JsonProperty 205 @JsonProperty
206 public String getPassword() 206 public String getPassword()
207 { 207 {
@@ -3,8 +3,6 @@ package com.ruoyi.common.filter; @@ -3,8 +3,6 @@ package com.ruoyi.common.filter;
3 import java.io.IOException; 3 import java.io.IOException;
4 import java.util.ArrayList; 4 import java.util.ArrayList;
5 import java.util.List; 5 import java.util.List;
6 -import java.util.regex.Matcher;  
7 -import java.util.regex.Pattern;  
8 import javax.servlet.Filter; 6 import javax.servlet.Filter;
9 import javax.servlet.FilterChain; 7 import javax.servlet.FilterChain;
10 import javax.servlet.FilterConfig; 8 import javax.servlet.FilterConfig;
@@ -27,16 +25,10 @@ public class XssFilter implements Filter @@ -27,16 +25,10 @@ public class XssFilter implements Filter
27 */ 25 */
28 public List<String> excludes = new ArrayList<>(); 26 public List<String> excludes = new ArrayList<>();
29 27
30 - /**  
31 - * xss过滤开关  
32 - */  
33 - public boolean enabled = false;  
34 -  
35 @Override 28 @Override
36 public void init(FilterConfig filterConfig) throws ServletException 29 public void init(FilterConfig filterConfig) throws ServletException
37 { 30 {
38 String tempExcludes = filterConfig.getInitParameter("excludes"); 31 String tempExcludes = filterConfig.getInitParameter("excludes");
39 - String tempEnabled = filterConfig.getInitParameter("enabled");  
40 if (StringUtils.isNotEmpty(tempExcludes)) 32 if (StringUtils.isNotEmpty(tempExcludes))
41 { 33 {
42 String[] url = tempExcludes.split(","); 34 String[] url = tempExcludes.split(",");
@@ -45,10 +37,6 @@ public class XssFilter implements Filter @@ -45,10 +37,6 @@ public class XssFilter implements Filter
45 excludes.add(url[i]); 37 excludes.add(url[i]);
46 } 38 }
47 } 39 }
48 - if (StringUtils.isNotEmpty(tempEnabled))  
49 - {  
50 - enabled = Boolean.valueOf(tempEnabled);  
51 - }  
52 } 40 }
53 41
54 @Override 42 @Override
@@ -68,25 +56,14 @@ public class XssFilter implements Filter @@ -68,25 +56,14 @@ public class XssFilter implements Filter
68 56
69 private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) 57 private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
70 { 58 {
71 - if (!enabled)  
72 - {  
73 - return true;  
74 - }  
75 - if (excludes == null || excludes.isEmpty())  
76 - {  
77 - return false;  
78 - }  
79 String url = request.getServletPath(); 59 String url = request.getServletPath();
80 - for (String pattern : excludes) 60 + String method = request.getMethod();
  61 + // GET DELETE 不过滤
  62 + if (method == null || method.matches("GET") || method.matches("DELETE"))
81 { 63 {
82 - Pattern p = Pattern.compile("^" + pattern);  
83 - Matcher m = p.matcher(url);  
84 - if (m.find())  
85 - {  
86 - return true;  
87 - } 64 + return true;
88 } 65 }
89 - return false; 66 + return StringUtils.matches(url, excludes);
90 } 67 }
91 68
92 @Override 69 @Override
@@ -6,6 +6,7 @@ import java.util.HashSet; @@ -6,6 +6,7 @@ import java.util.HashSet;
6 import java.util.List; 6 import java.util.List;
7 import java.util.Map; 7 import java.util.Map;
8 import java.util.Set; 8 import java.util.Set;
  9 +import org.springframework.util.AntPathMatcher;
9 import com.ruoyi.common.constant.Constants; 10 import com.ruoyi.common.constant.Constants;
10 import com.ruoyi.common.core.text.StrFormatter; 11 import com.ruoyi.common.core.text.StrFormatter;
11 12
@@ -463,6 +464,45 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils @@ -463,6 +464,45 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
463 return sb.toString(); 464 return sb.toString();
464 } 465 }
465 466
  467 + /**
  468 + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
  469 + *
  470 + * @param str 指定字符串
  471 + * @param strs 需要检查的字符串数组
  472 + * @return 是否匹配
  473 + */
  474 + public static boolean matches(String str, List<String> strs)
  475 + {
  476 + if (isEmpty(str) || isEmpty(strs))
  477 + {
  478 + return false;
  479 + }
  480 + for (String pattern : strs)
  481 + {
  482 + if (isMatch(pattern, str))
  483 + {
  484 + return true;
  485 + }
  486 + }
  487 + return false;
  488 + }
  489 +
  490 + /**
  491 + * 判断url是否与规则配置:
  492 + * ? 表示单个字符;
  493 + * * 表示一层路径内的任意字符串,不可跨层级;
  494 + * ** 表示任意层路径;
  495 + *
  496 + * @param pattern 匹配规则
  497 + * @param url 需要匹配的url
  498 + * @return
  499 + */
  500 + public static boolean isMatch(String pattern, String url)
  501 + {
  502 + AntPathMatcher matcher = new AntPathMatcher();
  503 + return matcher.match(pattern, url);
  504 + }
  505 +
466 @SuppressWarnings("unchecked") 506 @SuppressWarnings("unchecked")
467 public static <T> T cast(Object obj) 507 public static <T> T cast(Object obj)
468 { 508 {
@@ -4,6 +4,7 @@ import java.util.HashMap; @@ -4,6 +4,7 @@ import java.util.HashMap;
4 import java.util.Map; 4 import java.util.Map;
5 import javax.servlet.DispatcherType; 5 import javax.servlet.DispatcherType;
6 import org.springframework.beans.factory.annotation.Value; 6 import org.springframework.beans.factory.annotation.Value;
  7 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 import org.springframework.boot.web.servlet.FilterRegistrationBean; 8 import org.springframework.boot.web.servlet.FilterRegistrationBean;
8 import org.springframework.context.annotation.Bean; 9 import org.springframework.context.annotation.Bean;
9 import org.springframework.context.annotation.Configuration; 10 import org.springframework.context.annotation.Configuration;
@@ -17,11 +18,9 @@ import com.ruoyi.common.utils.StringUtils; @@ -17,11 +18,9 @@ import com.ruoyi.common.utils.StringUtils;
17 * @author ruoyi 18 * @author ruoyi
18 */ 19 */
19 @Configuration 20 @Configuration
  21 +@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
20 public class FilterConfig 22 public class FilterConfig
21 { 23 {
22 - @Value("${xss.enabled}")  
23 - private String enabled;  
24 -  
25 @Value("${xss.excludes}") 24 @Value("${xss.excludes}")
26 private String excludes; 25 private String excludes;
27 26
@@ -40,7 +39,6 @@ public class FilterConfig @@ -40,7 +39,6 @@ public class FilterConfig
40 registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); 39 registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
41 Map<String, String> initParameters = new HashMap<String, String>(); 40 Map<String, String> initParameters = new HashMap<String, String>();
42 initParameters.put("excludes", excludes); 41 initParameters.put("excludes", excludes);
43 - initParameters.put("enabled", enabled);  
44 registration.setInitParameters(initParameters); 42 registration.setInitParameters(initParameters);
45 return registration; 43 return registration;
46 } 44 }