新增XSS过滤
This commit is contained in:
parent
ddcdc844dd
commit
e7bbef4d43
|
@ -0,0 +1,29 @@
|
||||||
|
package net.maku.framework.common.xss;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.util.PathMatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XSS 配置文件
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(XssProperties.class)
|
||||||
|
@ConditionalOnProperty(prefix = "maku.xss", value = "enabled")
|
||||||
|
public class XssConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean<XssFilter> xssFilter(XssProperties properties, PathMatcher pathMatcher) {
|
||||||
|
FilterRegistrationBean<XssFilter> bean = new FilterRegistrationBean<>();
|
||||||
|
bean.setFilter(new XssFilter(properties, pathMatcher));
|
||||||
|
bean.setOrder(Integer.MAX_VALUE);
|
||||||
|
bean.setName("xssFilter");
|
||||||
|
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package net.maku.framework.common.xss;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.util.PathMatcher;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Xss 过滤器
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class XssFilter extends OncePerRequestFilter {
|
||||||
|
private final XssProperties properties;
|
||||||
|
private final PathMatcher pathMatcher;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
filterChain.doFilter(new XssRequestWrapper(request), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldNotFilter(HttpServletRequest request) {
|
||||||
|
// 放行不过滤的URL
|
||||||
|
return properties.getExcludeUrls().stream().anyMatch(excludeUrl -> pathMatcher.match(excludeUrl, request.getRequestURI()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package net.maku.framework.common.xss;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XSS 配置项
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "maku.xss")
|
||||||
|
public class XssProperties {
|
||||||
|
/**
|
||||||
|
* 是否开启 XSS
|
||||||
|
*/
|
||||||
|
private boolean enabled;
|
||||||
|
/**
|
||||||
|
* 排除的URL列表
|
||||||
|
*/
|
||||||
|
private List<String> excludeUrls = Collections.emptyList();
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
package net.maku.framework.common.xss;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import javax.servlet.ReadListener;
|
||||||
|
import javax.servlet.ServletInputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XSS Request Wrapper
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
public class XssRequestWrapper extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
|
public XssRequestWrapper(HttpServletRequest request) {
|
||||||
|
super(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
|
// 如果是json数据,则不处理
|
||||||
|
if (!StrUtil.startWithIgnoreCase(this.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
|
||||||
|
return super.getInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取内容,进行xss过滤
|
||||||
|
String content = IoUtil.readUtf8(super.getInputStream());
|
||||||
|
content = filterXss(content);
|
||||||
|
|
||||||
|
// 返回新的 ServletInputStream
|
||||||
|
final ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes());
|
||||||
|
return new ServletInputStream() {
|
||||||
|
@Override
|
||||||
|
public boolean isFinished() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadListener(ReadListener readListener) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() {
|
||||||
|
return bis.read();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getParameter(String name) {
|
||||||
|
String value = super.getParameter(name);
|
||||||
|
|
||||||
|
return filterXss(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getParameterValues(String name) {
|
||||||
|
String[] parameters = super.getParameterValues(name);
|
||||||
|
if (parameters == null || parameters.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < parameters.length; i++) {
|
||||||
|
parameters[i] = filterXss(parameters[i]);
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String[]> getParameterMap() {
|
||||||
|
Map<String, String[]> map = new LinkedHashMap<>();
|
||||||
|
Map<String, String[]> parameters = super.getParameterMap();
|
||||||
|
for (String key : parameters.keySet()) {
|
||||||
|
String[] values = parameters.get(key);
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
values[i] = filterXss(values[i]);
|
||||||
|
}
|
||||||
|
map.put(key, values);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeader(String name) {
|
||||||
|
String value = super.getHeader(name);
|
||||||
|
return filterXss(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String filterXss(String content) {
|
||||||
|
if (StrUtil.isBlank(content)) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return XssUtils.filter(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package net.maku.framework.common.xss;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import cn.hutool.http.HTMLFilter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XSS 过滤工具类
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
public class XssUtils {
|
||||||
|
private static final ThreadLocal<HTMLFilter> HTML_FILTER = ThreadLocal.withInitial(() -> {
|
||||||
|
HTMLFilter htmlFilter = new HTMLFilter();
|
||||||
|
// 避免 " 被转成 " 字符
|
||||||
|
ReflectUtil.setFieldValue(htmlFilter, "encodeQuotes", false);
|
||||||
|
return htmlFilter;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XSS过滤
|
||||||
|
*
|
||||||
|
* @param content 需要过滤的内容
|
||||||
|
* @return 返回过滤后的内容
|
||||||
|
*/
|
||||||
|
public static String filter(String content) {
|
||||||
|
return HTML_FILTER.get().filter(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,6 +30,10 @@ storage:
|
||||||
local:
|
local:
|
||||||
path: D://upload
|
path: D://upload
|
||||||
|
|
||||||
|
maku:
|
||||||
|
xss:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
mybatis-plus:
|
mybatis-plus:
|
||||||
mapper-locations: classpath*:/mapper/**/*.xml
|
mapper-locations: classpath*:/mapper/**/*.xml
|
||||||
# 实体扫描,多个package用逗号或者分号分隔
|
# 实体扫描,多个package用逗号或者分号分隔
|
||||||
|
@ -53,4 +57,4 @@ mybatis-plus:
|
||||||
configuration-properties:
|
configuration-properties:
|
||||||
prefix:
|
prefix:
|
||||||
blobType: BLOB
|
blobType: BLOB
|
||||||
boolValue: TRUE
|
boolValue: TRUE
|
Loading…
Reference in New Issue
Block a user