diff --git a/novel-front/src/main/java/com/java2nb/novel/core/config/FilterConfig.java b/novel-front/src/main/java/com/java2nb/novel/core/config/FilterConfig.java index 38397e9..845b02c 100644 --- a/novel-front/src/main/java/com/java2nb/novel/core/config/FilterConfig.java +++ b/novel-front/src/main/java/com/java2nb/novel/core/config/FilterConfig.java @@ -1,11 +1,17 @@ package com.java2nb.novel.core.config; import com.java2nb.novel.core.filter.NovelFilter; +import com.java2nb.novel.core.filter.XssFilter; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import javax.servlet.DispatcherType; +import java.util.HashMap; +import java.util.Map; + /** * 过滤器配置类 * @author Administrator @@ -16,6 +22,15 @@ public class FilterConfig{ @Value("${pic.save.path}") private String picSavePath; + @Value("${xss.enabled}") + private String enabled; + + @Value("${xss.excludes}") + private String excludes; + + @Value("${xss.urlPatterns}") + private String urlPatterns; + @Bean public FilterRegistrationBean filterRegist() { FilterRegistrationBean frBean = new FilterRegistrationBean<>(); @@ -25,4 +40,27 @@ public class FilterConfig{ return frBean; } + @Bean + public FilterRegistrationBean xssFilterRegistration() + { + FilterRegistrationBean registration = new FilterRegistrationBean(); + // + registration.setDispatcherTypes(DispatcherType.REQUEST); + //过滤器类(继承Filter) + registration.setFilter(new XssFilter()); + // + registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); + // + registration.setName("xssFilter"); + // + registration.setOrder(Integer.MAX_VALUE); + Map initParameters = new HashMap<>(2); + initParameters.put("excludes", excludes); + initParameters.put("enabled", enabled); + //Filter 初始化参数 + registration.setInitParameters(initParameters); + return registration; + } + + } diff --git a/novel-front/src/main/java/com/java2nb/novel/core/filter/XssFilter.java b/novel-front/src/main/java/com/java2nb/novel/core/filter/XssFilter.java new file mode 100644 index 0000000..8ac39e0 --- /dev/null +++ b/novel-front/src/main/java/com/java2nb/novel/core/filter/XssFilter.java @@ -0,0 +1,82 @@ +package com.java2nb.novel.core.filter; + +import com.java2nb.novel.core.wrapper.XssHttpServletRequestWrapper; +import lombok.SneakyThrows; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 防止XSS攻击的过滤器 + * @author Administrator + */ +public class XssFilter implements Filter { + /** + * 排除链接 + */ + public List excludes = new ArrayList<>(); + + /** + * xss过滤开关 + */ + public boolean enabled = false; + + @SneakyThrows + @Override + public void init(FilterConfig filterConfig){ + String tempExcludes = filterConfig.getInitParameter("excludes"); + String tempEnabled = filterConfig.getInitParameter("enabled"); + if (StringUtils.isNotBlank(tempExcludes)) { + String[] url = tempExcludes.split(","); + for (int i = 0; url != null && i < url.length; i++) { + excludes.add(url[i]); + } + } + if (StringUtils.isNotEmpty(tempEnabled)) { + enabled = Boolean.valueOf(tempEnabled); + } + } + + @SneakyThrows + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + if (handleExcludeURL(req, resp)) { + chain.doFilter(request, response); + return; + } + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); + chain.doFilter(xssRequest, response); + } + + private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { + if (!enabled) { + return true; + } + if (excludes == null || excludes.isEmpty()) { + return false; + } + String url = request.getServletPath(); + for (String pattern : excludes) { + Pattern p = Pattern.compile("^" + pattern); + Matcher m = p.matcher(url); + if (m.find()) { + return true; + } + } + return false; + } + + @Override + public void destroy() { + + } +} diff --git a/novel-front/src/main/java/com/java2nb/novel/core/wrapper/XssHttpServletRequestWrapper.java b/novel-front/src/main/java/com/java2nb/novel/core/wrapper/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000..059e265 --- /dev/null +++ b/novel-front/src/main/java/com/java2nb/novel/core/wrapper/XssHttpServletRequestWrapper.java @@ -0,0 +1,37 @@ +package com.java2nb.novel.core.wrapper; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +/** + * XSS过滤处理 + * @author Administrator + */ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper +{ + /** + * @param request + */ + public XssHttpServletRequestWrapper(HttpServletRequest request) + { + super(request); + } + + @Override + public String[] getParameterValues(String name) + { + String[] values = super.getParameterValues(name); + if (values != null) + { + int length = values.length; + String[] escapseValues = new String[length]; + for (int i = 0; i < length; i++) + { + // 防xss攻击和过滤前后空格 + escapseValues[i] = values[i].replaceAll("<","<").replaceAll(">",">"); + } + return escapseValues; + } + return super.getParameterValues(name); + } +} diff --git a/novel-front/src/main/resources/application.yml b/novel-front/src/main/resources/application.yml index 46dd605..f8181f2 100644 --- a/novel-front/src/main/resources/application.yml +++ b/novel-front/src/main/resources/application.yml @@ -15,4 +15,11 @@ cache: password: novel@2020117 - +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice/* + # 匹配链接 (多个用逗号分隔) + urlPatterns: /book/addBookComment,/user/addFeedBack