修复漏洞

This commit is contained in:
zjf committed 2026-10-29 13:27:20 +08:00
1 parent 710e4cfb90
commit bb0b8bd7ef
14 files changed
+777 -161

No files matched your search

@@ -35,76 +35,107 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* @author pjcloud
* @date 2019-06-24
* <p>
* 解决Mybatis Plus Order By SQL注入问题
* 解决Mybatis Plus Order By SQL注入问题:ascs/descs 仅允许简单列名白名单,禁止表达式/函数注入。
*/
@Slf4j
public class SqlFilterArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 排序字段白名单:仅允许标识符(可选表别名.列名),禁止空格、括号、逗号、注释等。
* 例:create_time、user_id、u.createTime
*/
private static final Pattern SAFE_ORDER_COLUMN = Pattern.compile(
"^[a-zA-Z_][a-zA-Z0-9_]{0,63}(\\.[a-zA-Z_][a-zA-Z0-9_]{0,63})?$");
/**
* 判断Controller是否包含page 参数
*
* @param parameter 参数
* @return 是否过滤
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(Page.class);
}
/** 单次请求最多允许的排序列数量,防止恶意堆叠。 */
private static final int MAX_ORDER_COLUMNS = 5;
/**
* @param parameter 入参集合
* @param mavContainer model 和 view
* @param webRequest web相关
* @param binderFactory 入参解析
* @return 检查后新的page对象
* <p>
* page 只支持查询 GET .如需解析POST获取请求报文体处理
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
/**
* 判断Controller是否包含page 参数
*
* @param parameter 参数
* @return 是否过滤
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(Page.class);
}
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
/**
* @param parameter 入参集合
* @param mavContainer model 和 view
* @param webRequest web相关
* @param binderFactory 入参解析
* @return 检查后新的page对象
* <p>
* page 只支持查询 GET .如需解析POST获取请求报文体处理
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
String ascs = request.getParameter("ascs");
String descs = request.getParameter("descs");
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
String current = request.getParameter("current");
String size = request.getParameter("size");
String ascs = request.getParameter("ascs");
String descs = request.getParameter("descs");
Page page = new Page();
if (StrUtil.isNotBlank(current)) {
// 如果current page 小于零 视为不合法数据
if (CompareUtil.compare(Long.parseLong(current), 0L) < 0) {
throw new CheckedException("current page error");
}
page.setCurrent(Long.parseLong(current));
}
String current = request.getParameter("current");
String size = request.getParameter("size");
if (StrUtil.isNotBlank(size)) {
page.setSize(Long.parseLong(size));
}
Page page = new Page();
if (StrUtil.isNotBlank(current)) {
// 如果current page 小于零 视为不合法数据
if (CompareUtil.compare(Long.parseLong(current), 0L) < 0) {
throw new CheckedException("current page error");
}
page.setCurrent(Long.parseLong(current));
}
List<OrderItem> orderItemList = new ArrayList<>();
Optional.ofNullable(ascs)
.ifPresent(s -> orderItemList.addAll(Arrays.stream(s.split(StrUtil.COMMA))
.filter(asc -> !SqlInjectionUtils.check(asc))
.map(OrderItem::asc)
.collect(Collectors.toList())));
Optional.ofNullable(descs)
.ifPresent(s -> orderItemList.addAll(Arrays.stream(s.split(StrUtil.COMMA))
.filter(desc -> !SqlInjectionUtils.check(desc))
.map(OrderItem::desc)
.collect(Collectors.toList())));
page.addOrder(orderItemList);
if (StrUtil.isNotBlank(size)) {
page.setSize(Long.parseLong(size));
}
List<OrderItem> orderItemList = new ArrayList<>();
Optional.ofNullable(ascs)
.ifPresent(s -> orderItemList.addAll(Arrays.stream(s.split(StrUtil.COMMA))
.map(String::trim)
.filter(StrUtil::isNotBlank)
.map(col -> toSafeOrderColumn(col, true))
.collect(Collectors.toList())));
Optional.ofNullable(descs)
.ifPresent(s -> orderItemList.addAll(Arrays.stream(s.split(StrUtil.COMMA))
.map(String::trim)
.filter(StrUtil::isNotBlank)
.map(col -> toSafeOrderColumn(col, false))
.collect(Collectors.toList())));
if (orderItemList.size() > MAX_ORDER_COLUMNS) {
throw new CheckedException("排序字段数量超限");
}
page.addOrder(orderItemList);
return page;
}
/**
* 将前端排序字段转为安全的 OrderItem:必须通过标识符白名单,且通过 SqlInjectionUtils 黑名单兜底。
*/
private static OrderItem toSafeOrderColumn(String column, boolean asc) {
if (!SAFE_ORDER_COLUMN.matcher(column).matches()) {
log.warn("拒绝非法排序字段: {}", column);
throw new CheckedException("排序字段不合法");
}
if (SqlInjectionUtils.check(column)) {
log.warn("排序字段命中注入检测: {}", column);
throw new CheckedException("排序字段不合法");
}
return asc ? OrderItem.asc(column) : OrderItem.desc(column);
}
return page;
}
}