修复xssbug

This commit is contained in:
开源oschina 2022-05-20 18:29:20 +08:00
parent 47993beebd
commit 219f28c3c1
8 changed files with 119 additions and 35 deletions

View File

@ -112,7 +112,6 @@
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.26.0</version>
</dependency>
<!-- thymeleaf模版 -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -1,7 +1,8 @@
package com.fc.v2.common.conf.xss;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@ -10,35 +11,61 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fc.v2.util.StringUtils;
import org.springframework.stereotype.Component;
@Component
public class SimpleCORSFilter implements Filter {
/**
* 排除链接
*/
public List<String> excludes = new ArrayList<>();
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// 在这里使用我们实现的XSS过滤器
XssHttpServletRequestWrapper request =
new XssHttpServletRequestWrapper((HttpServletRequest) req);
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods",
"POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, token");
chain.doFilter(request, response);
public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
// 在这里使用我们实现的XSS过滤器
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) req);
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
if (handleExcludeURL(request, response))
{
chain.doFilter(request, response);
return;
}
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods","POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, token");
chain.doFilter(xssRequest, response);
}
public void init(FilterConfig filterConfig) {
String tempExcludes = filterConfig.getInitParameter("exclusions");
if (StringUtils.isNotEmpty(tempExcludes))
{
String[] url = tempExcludes.split(",");
for (int i = 0; url != null && i < url.length; i++)
{
excludes.add(url[i]);
}
}
}
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
{
String url = request.getServletPath();
String method = request.getMethod();
// GET DELETE 不过滤
if (method == null || method.matches("GET") || method.matches("DELETE"))
{
return true;
}
return StringUtils.matches(url, excludes);
}
public void destroy() {
}
}

View File

@ -3,12 +3,7 @@ package com.fc.v2.common.conf.xss;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fc.v2.common.conf.V2Config;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@ -29,8 +24,8 @@ public class XssFilterAtuoConfig {
* @return
*/
@Bean
public FilterRegistrationBean xssFiltrRegister() {
FilterRegistrationBean registration = new FilterRegistrationBean();
public FilterRegistrationBean<SimpleCORSFilter> xssFiltrRegister() {
FilterRegistrationBean<SimpleCORSFilter> registration = new FilterRegistrationBean<SimpleCORSFilter>();
//设置系统过滤器 (setFilter就是你所定义的过滤器filter类)
registration.setFilter(new SimpleCORSFilter());
@ -45,12 +40,11 @@ public class XssFilterAtuoConfig {
if(xssnoturlList!=null&&xssnoturlList.size()>0) {
xssnot=String.join(",", xssnoturlList);
}
//添加忽略的格式以及链接请求
registration.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*,"+xssnot);
//优先级
registration.setOrder(1);
return registration;
}

View File

@ -1,19 +1,24 @@
package com.fc.v2.common.exception;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.AntPathMatcher;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import com.fc.v2.common.conf.V2Config;
import com.fc.v2.common.domain.AjaxResult;
import com.fc.v2.common.exception.demo.DemoModeException;
import com.fc.v2.util.ServletUtils;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
@ -29,6 +34,9 @@ import cn.dev33.satoken.exception.SaTokenException;
public class GlobalExceptionResolver{
private static Logger logger = LoggerFactory.getLogger(GlobalExceptionResolver.class);
@Autowired
private V2Config v2Config;
/**
* 权限校验失败 如果请求为ajax返回json普通请求跳转页面
*/
@ -45,10 +53,24 @@ public class GlobalExceptionResolver{
{
// 登录认证异常
if(e instanceof NotLoginException){
List<String> satoken_not_urls=v2Config.getSaTokenNotFilterUrl();
for (String nourl : satoken_not_urls) {
AntPathMatcher matcher = new AntPathMatcher();
if(matcher.match(nourl,request.getRequestURI())) {
return JSON.toJSONString(AjaxResult.error(886,e.getMessage()));
}
}
return new ModelAndView("/login");
}
// 权限认证异常
else if (e instanceof NotPermissionException || e instanceof NotRoleException || e instanceof NotSafeException){
List<String> satoken_not_urls=v2Config.getSaTokenNotFilterUrl();
for (String nourl : satoken_not_urls) {
AntPathMatcher matcher = new AntPathMatcher();
if(matcher.match(nourl,request.getRequestURI())) {
return JSON.toJSONString(AjaxResult.error(403,e.getMessage()));
}
}
return new ModelAndView("/error/403");
}
// 其它异常

View File

@ -6,7 +6,6 @@ import com.fc.v2.common.domain.ResultTable;
import com.fc.v2.model.auto.GoviewProject;
import com.fc.v2.model.auto.GoviewProjectData;
import com.fc.v2.model.auto.GoviewProjectDataExample;
import com.fc.v2.model.auto.GoviewProjectExample;
import com.fc.v2.model.custom.Tablepar;
import com.fc.v2.service.GoviewProjectDataService;
import com.fc.v2.service.GoviewProjectService;
@ -14,9 +13,7 @@ import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import cn.dev33.satoken.annotation.SaCheckPermission;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
@ -171,7 +168,7 @@ public class GoviewProjectAPi extends BaseController{
@ApiOperation(value = "保存项目数据", notes = "保存项目数据")
@PostMapping("/save/data")
@ResponseBody
public AjaxResult saveData(@RequestBody GoviewProjectData data) {
public AjaxResult saveData(GoviewProjectData data) {
GoviewProject goviewProject= goviewProjectService.selectByPrimaryKey(data.getProjectId());
if(goviewProject==null) {

View File

@ -86,6 +86,11 @@ public class SaTokenConfigure implements WebMvcConfigurer {
.setError(e -> {
// e.printStackTrace();
if(e instanceof NotLoginException) {
for (String nourl : satoken_not_urls) {
if(nourl.contains(SaHolder.getRequest().getUrl())) {
return JSON.toJSONString(AjaxResult.error(886,e.getMessage()));
}
}
SaHolder.getResponse().redirect("/admin/login");
}
return JSON.toJSONString(AjaxResult.error(e.getMessage()));

View File

@ -1,9 +1,11 @@
package com.fc.v2.util;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang.text.StrBuilder;
import org.springframework.util.AntPathMatcher;
@ -441,4 +443,42 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
}
return columnToJava(tableName);
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs)
{
if (isEmpty(str) || isEmpty(strs))
{
return false;
}
for (String pattern : strs)
{
if (isMatch(pattern, str))
{
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
*/
public static boolean isMatch(String pattern, String url)
{
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
}

View File

@ -20,7 +20,7 @@ fuce:
#漂亮得拖动验证码 默认false普通验证码、true滚动验证码
roll-verification: false
#xss不拦截url
xss-not-filter-url: [/api/v1/token/api_token,/api/v1/yibaotong/save]
xss-not-filter-url: [/api/v1/token/api_token,/api/goview/project/save/data]
#satoken不拦截url
sa-token-not-filter-url: [/api/goview/sys/*,/api/goview/project/**]
#tomcat config