fix: 潜在越权漏洞

This commit is contained in:
fit2cloud-chenyw
2024-12-26 11:53:29 +08:00
committed by 王嘉豪
parent 11ec63d5c9
commit 7412db0d3c
6 changed files with 84 additions and 28 deletions

View File

@@ -2,13 +2,19 @@ package io.dataease.auth.filter;
import io.dataease.auth.bo.TokenUserBO;
import io.dataease.constant.AuthConstant;
import io.dataease.exception.DEException;
import io.dataease.result.ResultMessage;
import io.dataease.utils.*;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
public class TokenFilter implements Filter {
@@ -35,32 +41,52 @@ public class TokenFilter implements Filter {
}
String requestURI = request.getRequestURI();
if (ModelUtils.isDesktop()) {
UserUtils.setDesktopUser();
boolean match = false;
try {
match = WhitelistUtils.match(requestURI);
} catch (DEException e) {
HttpServletResponse res = (HttpServletResponse) servletResponse;
ResultMessage resultMessage = new ResultMessage(e.getCode(), e.getMessage());
ResponseEntity<ResultMessage> entity = new ResponseEntity<>(resultMessage, HttpStatus.UNAUTHORIZED);
sendResponseEntity(res, entity);
LogUtil.error(e.getMessage(), e);
return;
}
if (match) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
try {
if (ModelUtils.isDesktop()) {
UserUtils.setDesktopUser();
filterChain.doFilter(servletRequest, servletResponse);
return;
}
String executeVersion = null;
if (StringUtils.isNotBlank(executeVersion = VersionUtil.getRandomVersion())) {
Objects.requireNonNull(ServletUtils.response()).addHeader(AuthConstant.DE_EXECUTE_VERSION, executeVersion);
}
String linkToken = ServletUtils.getHead(AuthConstant.LINK_TOKEN_KEY);
if (StringUtils.isNotBlank(linkToken)) {
TokenUserBO tokenUserBO = TokenUtils.validateLinkToken(linkToken);
UserUtils.setUserInfo(tokenUserBO);
filterChain.doFilter(servletRequest, servletResponse);
return;
}
String token = ServletUtils.getToken();
TokenUserBO userBO = TokenUtils.validate(token);
UserUtils.setUserInfo(userBO);
filterChain.doFilter(servletRequest, servletResponse);
} finally {
UserUtils.removeUser();
}
}
if (WhitelistUtils.match(requestURI)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
String executeVersion = null;
if (StringUtils.isNotBlank(executeVersion = VersionUtil.getRandomVersion())) {
Objects.requireNonNull(ServletUtils.response()).addHeader(AuthConstant.DE_EXECUTE_VERSION, executeVersion);
}
String linkToken = ServletUtils.getHead(AuthConstant.LINK_TOKEN_KEY);
if (StringUtils.isNotBlank(linkToken)) {
TokenUserBO tokenUserBO = TokenUtils.validateLinkToken(linkToken);
UserUtils.setUserInfo(tokenUserBO);
filterChain.doFilter(servletRequest, servletResponse);
return;
}
String token = ServletUtils.getToken();
TokenUserBO userBO = TokenUtils.validate(token);
UserUtils.setUserInfo(userBO);
filterChain.doFilter(servletRequest, servletResponse);
private void sendResponseEntity(HttpServletResponse httpResponse, ResponseEntity<ResultMessage> responseEntity) throws IOException {
HttpStatusCode statusCode = responseEntity.getStatusCode();
httpResponse.setStatus(statusCode.value());
httpResponse.setCharacterEncoding(StandardCharsets.UTF_8.name());
httpResponse.getWriter().write(Objects.requireNonNull(JsonUtil.toJSONString(responseEntity.getBody()).toString()));
}
}

View File

@@ -2,12 +2,18 @@ package io.dataease.exception;
import io.dataease.result.ResultCode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serial;
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class DEException extends RuntimeException {
@Serial
private static final long serialVersionUID = 8170873998824378304L;
private int code;
private String msg;

View File

@@ -5,6 +5,7 @@ import io.dataease.i18n.Translator;
import io.dataease.result.ResultCode;
import io.dataease.result.ResultMessage;
import io.dataease.utils.LogUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -14,20 +15,29 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
public class GlobalExceptionHandler {
/** -------- 参数校验异常 -------- **/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultMessage MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
String msg = objectError.getDefaultMessage();
msg = Translator.get(msg);
LogUtil.error(msg);
return new ResultMessage(ResultCode.PARAM_IS_INVALID.code(),msg);
return new ResultMessage(ResultCode.PARAM_IS_INVALID.code(), msg);
}
@ExceptionHandler(DEException.class)
public ResultMessage deExceptionHandler(DEException e) {
LogUtil.error(e.getMessage(), e);
return new ResultMessage(e.getCode(),e.getMessage());
return new ResultMessage(e.getCode(), e.getMessage());
}
@ExceptionHandler(NullPointerException.class)
public ResultMessage noUserExceptionHandler(Exception e) {
String message = e.getMessage();
LogUtil.error(message, e);
if (StringUtils.contains(message, "Cannot invoke \"io.dataease.auth.bo.TokenUserBO.getUserId()\" because \"user\" is null")) {
return new ResultMessage(ResultCode.USER_NOT_LOGGED_IN.code(), ResultCode.USER_NOT_LOGGED_IN.message());
}
return new ResultMessage(ResultCode.PARAM_IS_BLANK.code(), message);
}
}

View File

@@ -19,6 +19,10 @@ public class AuthUtils {
USER_INFO.set(userBO);
}
public static void remove() {
USER_INFO.remove();
}
public static boolean isSysAdmin() {
TokenUserBO user = null;
if (ObjectUtils.isEmpty(user = getUser())) {

View File

@@ -14,4 +14,8 @@ public class UserUtils {
bo.setDefaultOid(1L);
AuthUtils.setUser(bo);
}
public static void removeUser() {
AuthUtils.remove();
}
}

View File

@@ -8,6 +8,8 @@ import org.springframework.core.env.Environment;
import java.util.List;
import java.util.Objects;
import static io.dataease.result.ResultCode.INTERFACE_ADDRESS_INVALID;
public class WhitelistUtils {
private static String contextPath;
@@ -50,9 +52,7 @@ public class WhitelistUtils {
"/");
public static boolean match(String requestURI) {
if (requestURI.contains(";") && !requestURI.contains("?")) {
DEException.throwException("Invalid uri: " + requestURI);
}
invalidUrl(requestURI);
if (StringUtils.startsWith(requestURI, getContextPath())) {
requestURI = requestURI.replaceFirst(getContextPath(), "");
}
@@ -100,4 +100,10 @@ public class WhitelistUtils {
}
return redirect_uri + AuthConstant.DE_API_PREFIX + "/";
}
private static void invalidUrl(String requestURI) {
if (requestURI.contains("./") || (requestURI.contains(";") && !requestURI.contains("?"))) {
DEException.throwException(INTERFACE_ADDRESS_INVALID.code(), String.format("%s [%s]", INTERFACE_ADDRESS_INVALID.message(), requestURI));
}
}
}