feat: 增加 XSS 过滤配置

This commit is contained in:
xiongxiaoyang 2022-05-17 20:00:21 +08:00
parent 9f5e532185
commit 339cdc6dba
4 changed files with 147 additions and 0 deletions

View File

@ -0,0 +1,28 @@
package io.github.xxyopen.novel.core.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* Xss 过滤配置属性
*
* @author xiongxiaoyang
* @date 2022/5/17
*/
@ConfigurationProperties(prefix = "novel.xss")
@Data
public class XssProperties {
/**
* 过滤开关
* */
private Boolean enabled;
/**
* 排除链接
* */
private List<String> excludes;
}

View File

@ -0,0 +1,69 @@
package io.github.xxyopen.novel.core.filter;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import io.github.xxyopen.novel.core.config.XssProperties;
import io.github.xxyopen.novel.core.wrapper.XssHttpServletRequestWrapper;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 防止 XSS 攻击的过滤器
*
* @author xiongxiaoyang
* @date 2022/5/17
*/
@Component
@ConditionalOnProperty(value = "novel.xss.enabled",havingValue = "true")
@WebFilter(urlPatterns = "/*", filterName = "xssFilter")
@EnableConfigurationProperties(value = {XssProperties.class})
@RequiredArgsConstructor
public class XssFilter implements Filter {
private final XssProperties xssProperties;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
if (handleExcludeUrl(req)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest);
filterChain.doFilter(xssRequest, servletResponse);
}
private boolean handleExcludeUrl(HttpServletRequest request) {
if (CollectionUtils.isEmpty(xssProperties.getExcludes())) {
return false;
}
String url = request.getServletPath();
for (String pattern : xssProperties.getExcludes()) {
Pattern p = Pattern.compile("^" + pattern);
Matcher m = p.matcher(url);
if (m.find()) {
return true;
}
}
return false;
}
@Override
public void destroy() {
Filter.super.destroy();
}
}

View File

@ -0,0 +1,40 @@
package io.github.xxyopen.novel.core.wrapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.Map;
/**
* XSS 过滤处理
*
* @author xiongxiaoyang
* @date 2022/5/17
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final Map<String,String> replaceRule = new HashMap<>();
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
replaceRule.put("<", "&lt;");
replaceRule.put(">", "&gt;");
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values != null) {
int length = values.length;
String[] escapeValues = new String[length];
for (int i = 0; i < length; i++) {
String raw = values[i];
int index = i;
replaceRule.forEach((k, v)-> escapeValues[index] = raw.replaceAll(k, v));
}
return escapeValues;
}
return new String[0];
}
}

View File

@ -54,4 +54,14 @@ novel:
# JWT密钥 # JWT密钥
jwt: jwt:
secret: E66559580A1ADF48CDD928516062F12E secret: E66559580A1ADF48CDD928516062F12E
# XSS 过滤配置
xss:
# 过滤开关
enabled: true
# 排除链接
excludes:
- /system/notice/*