HW21-0499 表字典接口存在SQL注入漏洞,增加签名拦截器

This commit is contained in:
zhangdaiscott
2021-06-25 11:50:34 +08:00
parent 326bd31148
commit 89240beaa6
7 changed files with 369 additions and 62 deletions

View File

@ -290,6 +290,8 @@ public interface CommonConstant {
public final static String X_ACCESS_TOKEN = "X-Access-Token";
public final static String X_SIGN = "X-Sign";
public final static String X_TIMESTAMP = "X-TIMESTAMP";
/**
* 多租户 请求头

View File

@ -0,0 +1,84 @@
package org.jeecg.common.util;
import org.springframework.util.AntPathMatcher;
import java.util.Collection;
import java.util.Map;
/**
* 使用Spring自身提供的地址匹配工具匹配URL
*/
public class PathMatcherUtil {
public static void main(String[] args) {
String url = "/sys/dict/loadDictOrderByValue/tree,s2,2";
String p = "/sys/dict/loadDictOrderByValue/*";
System.out.println(PathMatcherUtil.match(p,url));
}
/**
* 实际验证路径匹配权限
*
* @param matchPath 权限url
* @param path 访问路径
* @return 是否拥有权限
*/
public static boolean match(String matchPath, String path) {
SpringAntMatcher springAntMatcher = new SpringAntMatcher(matchPath, true);
return springAntMatcher.matches(path);
}
/**
* 实际验证路径匹配权限
*
* @param list 权限url
* @param path 访问路径
* @return 是否拥有权限
*/
public static boolean matches(Collection<String> list, String path) {
for (String s : list) {
SpringAntMatcher springAntMatcher = new SpringAntMatcher(s, true);
if (springAntMatcher.matches(path)) {
return true;
}
}
return false;
}
/**
* 地址表达式匹配工具
*/
private static class SpringAntMatcher implements Matcher {
private final AntPathMatcher antMatcher;
private final String pattern;
private SpringAntMatcher(String pattern, boolean caseSensitive) {
this.pattern = pattern;
this.antMatcher = createMatcher(caseSensitive);
}
@Override
public boolean matches(String path) {
return this.antMatcher.match(this.pattern, path);
}
@Override
public Map<String, String> extractUriTemplateVariables(String path) {
return this.antMatcher.extractUriTemplateVariables(this.pattern, path);
}
private static AntPathMatcher createMatcher(boolean caseSensitive) {
AntPathMatcher matcher = new AntPathMatcher();
matcher.setTrimTokens(false);
matcher.setCaseSensitive(caseSensitive);
return matcher;
}
}
private interface Matcher {
boolean matches(String var1);
Map<String, String> extractUriTemplateVariables(String var1);
}
}

View File

@ -6,11 +6,14 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* online 拦截器配置
* 签名 拦截器配置
*/
@Configuration
public class SignAuthConfiguration implements WebMvcConfigurer {
public static String[] urlList = new String[] {"/sys/dict/getDictItems/*", "/sys/dict/loadDict/*",
"/sys/dict/loadDictOrderByValue/*", "/sys/dict/loadDictItem/*", "/sys/dict/loadTreeData",
"/sys/api/queryTableDictItemsByCode", "/sys/api/queryFilterTableDictInfo", "/sys/api/queryTableDictByKeys",
"/sys/api/translateDictFromTable", "/sys/api/translateDictFromTableByKeys"};
@Bean
public SignAuthInterceptor signAuthInterceptor() {
return new SignAuthInterceptor();
@ -18,10 +21,6 @@ public class SignAuthConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
String[] inculudes = new String[] {"/sys/dict/getDictItems/*", "/sys/dict/loadDict/*",
"/sys/dict/loadDictOrderByValue/*", "/sys/dict/loadDictItem/*", "/sys/dict/loadTreeData",
"/sys/api/queryTableDictItemsByCode", "/sys/api/queryFilterTableDictInfo", "/sys/api/queryTableDictByKeys",
"/sys/api/translateDictFromTable", "/sys/api/translateDictFromTableByKeys"};
registry.addInterceptor(signAuthInterceptor()).addPathPatterns(inculudes);
registry.addInterceptor(signAuthInterceptor()).addPathPatterns(urlList);
}
}

View File

@ -1,22 +1,20 @@
package org.jeecg.config.sign.interceptor;
import java.io.PrintWriter;
import java.util.SortedMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.DateUtils;
import org.jeecg.config.sign.util.BodyReaderHttpServletRequestWrapper;
import org.jeecg.config.sign.util.HttpUtils;
import org.jeecg.config.sign.util.SignUtil;
import org.springframework.web.servlet.HandlerInterceptor;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.SortedMap;
/**
* 签名拦截器
@ -31,13 +29,13 @@ public class SignAuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.debug("request URI = " + request.getRequestURI());
log.info("request URI = " + request.getRequestURI());
HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
//获取全部参数(包括URL和body上的)
SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper);
//对参数进行签名验证
String headerSign = request.getHeader("X-Sign");
String timesTamp = request.getHeader("X-TIMESTAMP");
String headerSign = request.getHeader(CommonConstant.X_SIGN);
String timesTamp = request.getHeader(CommonConstant.X_TIMESTAMP);
//1.校验时间有消息
try {
@ -60,15 +58,6 @@ public class SignAuthInterceptor implements HandlerInterceptor {
} else {
log.error("request URI = " + request.getRequestURI());
log.error("Sign 签名校验失败Header Sign : {}",headerSign);
// //打印日志参数
// Set<String> keySet = allParams.keySet();
// Iterator<String> paramIt = keySet.iterator();
// while(paramIt.hasNext()){
// String pkey = paramIt.next();
// String pval = allParams.get(pkey);
// log.error(" ["+pkey+":"+pval+"] ");
// }
//校验失败返回前端
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");

View File

@ -1,5 +1,10 @@
package org.jeecg.config.sign.util;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.http.HttpMethod;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@ -10,35 +15,28 @@ import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.http.HttpMethod;
import com.alibaba.fastjson.JSONObject;
/**
* http 工具类 获取请求中的参数
*
* @author show
* @date 14:23 2019/5/29
*
* @author jeecg
* @date 20210621
*/
public class HttpUtils {
/**
* 将URL的参数和body参数合并
*
* @author show
* @date 14:24 2019/5/29
*
* @author jeecg
* @date 20210621
* @param request
*/
public static SortedMap<String, String> getAllParams(HttpServletRequest request) throws IOException {
SortedMap<String, String> result = new TreeMap<>();
// 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username
String pathVariable = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/")+1);
if(pathVariable.contains(",")){
result.put(SignUtil.xPathVariable,pathVariable);
String pathVariable = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/") + 1);
if (pathVariable.contains(",")) {
result.put(SignUtil.xPathVariable, pathVariable);
}
// 获取URL上的参数
Map<String, String> urlParams = getUrlParams(request);
@ -59,11 +57,45 @@ public class HttpUtils {
return result;
}
/**
* 将URL的参数和body参数合并
*
* @author jeecg
* @date 20210621
* @param queryString
*/
public static SortedMap<String, String> getAllParams(String url, String queryString, byte[] body, String method)
throws IOException {
SortedMap<String, String> result = new TreeMap<>();
// 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username
String pathVariable = url.substring(url.lastIndexOf("/") + 1);
if (pathVariable.contains(",")) {
result.put(SignUtil.xPathVariable, pathVariable);
}
// 获取URL上的参数
Map<String, String> urlParams = getUrlParams(queryString);
for (Map.Entry entry : urlParams.entrySet()) {
result.put((String)entry.getKey(), (String)entry.getValue());
}
Map<String, String> allRequestParam = new HashMap<>(16);
// get请求不需要拿body参数
if (!HttpMethod.GET.name().equals(method)) {
allRequestParam = getAllRequestParam(body);
}
// 将URL的参数和body参数进行合并
if (allRequestParam != null) {
for (Map.Entry entry : allRequestParam.entrySet()) {
result.put((String)entry.getKey(), (String)entry.getValue());
}
}
return result;
}
/**
* 获取 Body 参数
*
* @author show
* @date 15:04 2019/5/30
*
* @date 15:04 20210621
* @param request
*/
public static Map<String, String> getAllRequestParam(final HttpServletRequest request) throws IOException {
@ -79,15 +111,29 @@ public class HttpUtils {
return JSONObject.parseObject(wholeStr.toString(), Map.class);
}
/**
* 获取 Body 参数
*
* @date 15:04 20210621
* @param body
*/
public static Map<String, String> getAllRequestParam(final byte[] body) throws IOException {
if(body==null){
return null;
}
String wholeStr = new String(body);
// 转化成json对象
return JSONObject.parseObject(wholeStr.toString(), Map.class);
}
/**
* 将URL请求参数转换成Map
*
* @author show
*
* @param request
*/
public static Map<String, String> getUrlParams(HttpServletRequest request) {
Map<String, String> result = new HashMap<>(16);
if(oConvertUtils.isEmpty(request.getQueryString())){
if (oConvertUtils.isEmpty(request.getQueryString())) {
return result;
}
String param = "";
@ -103,4 +149,28 @@ public class HttpUtils {
}
return result;
}
/**
* 将URL请求参数转换成Map
*
* @param queryString
*/
public static Map<String, String> getUrlParams(String queryString) {
Map<String, String> result = new HashMap<>(16);
if (oConvertUtils.isEmpty(queryString)) {
return result;
}
String param = "";
try {
param = URLDecoder.decode(queryString, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String[] params = param.split("&");
for (String s : params) {
int index = s.indexOf("=");
result.put(s.substring(0, index), s.substring(index + 1));
}
return result;
}
}