mirror of
https://github.com/dataease/dataease.git
synced 2026-05-14 12:22:10 +08:00
fix: 分享链接认证机制存在认证伪造绕过漏洞
This commit is contained in:
committed by
fit2cloud-chenyw
parent
d0372ef3a6
commit
00c169caa5
@@ -1,18 +1,12 @@
|
||||
package io.dataease.share.interceptor;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.auth0.jwt.interfaces.Verification;
|
||||
import io.dataease.auth.DeLinkPermit;
|
||||
import io.dataease.constant.AuthConstant;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.share.manage.XpackShareManage;
|
||||
import io.dataease.share.util.LinkTokenUtil;
|
||||
import io.dataease.utils.LogUtil;
|
||||
import io.dataease.utils.ServletUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
@@ -38,8 +32,6 @@ public class DeLinkAop {
|
||||
|
||||
private final ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
@Resource
|
||||
private XpackShareManage xpackShareManage;
|
||||
|
||||
@Around(value = "@annotation(io.dataease.auth.DeLinkPermit)")
|
||||
public Object logAround(ProceedingJoinPoint point) throws Throwable {
|
||||
@@ -60,18 +52,6 @@ public class DeLinkAop {
|
||||
DEException.throwException("link token invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
Long uid = jwt.getClaim("uid").asLong();
|
||||
String secret = xpackShareManage.queryPwd(resourceId, uid);
|
||||
if (StringUtils.isBlank(secret)) {
|
||||
secret = LinkTokenUtil.defaultPwd;
|
||||
}
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
Verification verification = JWT.require(algorithm);
|
||||
JWTVerifier verifier = verification.build();
|
||||
DecodedJWT decode = JWT.decode(linkToken);
|
||||
algorithm.verify(decode);
|
||||
verifier.verify(linkToken);
|
||||
}
|
||||
try {
|
||||
return point.proceed(params);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.dataease.share.manage;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.share.dao.auto.entity.XpackShare;
|
||||
import io.dataease.share.dao.auto.mapper.XpackShareMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("shareSecretManage")
|
||||
public class ShareSecretManage {
|
||||
|
||||
|
||||
@Getter
|
||||
@Value("${dataease.default-link-pwd:link-pwd-fit2cloud}")
|
||||
private String defaultPwd;
|
||||
|
||||
|
||||
@Resource
|
||||
private XpackShareMapper xpackShareMapper;
|
||||
|
||||
public String getSecret(Long resourceId, Long uid) {
|
||||
QueryWrapper<XpackShare> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("creator", uid);
|
||||
queryWrapper.eq("resource_id", resourceId);
|
||||
XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper);
|
||||
if (ObjectUtils.isEmpty(xpackShare)) DEException.throwException("Share resource do not exist");
|
||||
String sharePwd = xpackShare.getPwd();
|
||||
return StringUtils.isNotBlank(sharePwd) ? sharePwd : defaultPwd;
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,9 @@ public class XpackShareManage {
|
||||
@Resource
|
||||
private SysParameterManage sysParameterManage;
|
||||
|
||||
@Resource
|
||||
private ShareSecretManage shareSecretManage;
|
||||
|
||||
public void deleteByResource(Long resourceId) {
|
||||
if (resourceId == null) {
|
||||
return;
|
||||
@@ -88,14 +91,6 @@ public class XpackShareManage {
|
||||
return xpackShareMapper.selectOne(queryWrapper);
|
||||
}
|
||||
|
||||
public String queryPwd(Long resourceId, Long userId) {
|
||||
QueryWrapper<XpackShare> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("creator", userId);
|
||||
queryWrapper.eq("resource_id", resourceId);
|
||||
XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper);
|
||||
if (ObjectUtils.isEmpty(xpackShare)) return null;
|
||||
return xpackShare.getPwd();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void switcher(Long resourceId) {
|
||||
@@ -266,7 +261,9 @@ public class XpackShareManage {
|
||||
vo.setInIframeError(false);
|
||||
return vo;
|
||||
}
|
||||
String linkToken = LinkTokenUtil.generate(xpackShare.getCreator(), xpackShare.getResourceId(), xpackShare.getExp(), xpackShare.getPwd(), xpackShare.getOid());
|
||||
String defaultPwd = shareSecretManage.getDefaultPwd();
|
||||
String secret = StringUtils.isBlank(xpackShare.getPwd()) ? defaultPwd : xpackShare.getPwd();
|
||||
String linkToken = LinkTokenUtil.generate(xpackShare.getCreator(), xpackShare.getResourceId(), xpackShare.getExp(), secret, xpackShare.getOid());
|
||||
HttpServletResponse response = ServletUtils.response();
|
||||
response.addHeader(AuthConstant.LINK_TOKEN_KEY, linkToken);
|
||||
Integer type = xpackShare.getType();
|
||||
|
||||
@@ -4,14 +4,11 @@ import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTCreator;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class LinkTokenUtil {
|
||||
public static final String defaultPwd = "link-pwd-fit2cloud";
|
||||
public static String generate(Long uid, Long resourceId, Long exp, String pwd, Long oid) {
|
||||
pwd = StringUtils.isBlank(pwd) ? defaultPwd : pwd;
|
||||
Algorithm algorithm = Algorithm.HMAC256(pwd);
|
||||
JWTCreator.Builder builder = JWT.create();
|
||||
builder.withClaim("uid", uid).withClaim("resourceId", resourceId).withClaim("oid", oid);
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package io.dataease.auth.filter;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.auth0.jwt.interfaces.Verification;
|
||||
import io.dataease.auth.bo.TokenUserBO;
|
||||
import io.dataease.constant.AuthConstant;
|
||||
import io.dataease.exception.DEException;
|
||||
@@ -15,8 +20,10 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
@@ -72,8 +79,30 @@ public class TokenFilter implements Filter {
|
||||
}
|
||||
String linkToken = ServletUtils.getHead(AuthConstant.LINK_TOKEN_KEY);
|
||||
if (StringUtils.isNotBlank(linkToken)) {
|
||||
TokenUserBO tokenUserBO = TokenUtils.validateLinkToken(linkToken);
|
||||
UserUtils.setUserInfo(tokenUserBO);
|
||||
if (StringUtils.length(linkToken) < 100) {
|
||||
DEException.throwException("token is invalid");
|
||||
}
|
||||
DecodedJWT jwt = JWT.decode(linkToken);
|
||||
Long userId = jwt.getClaim("uid").asLong();
|
||||
Long oid = jwt.getClaim("oid").asLong();
|
||||
Long resourceId = jwt.getClaim("resourceId").asLong();
|
||||
if (ObjectUtils.isEmpty(userId)) {
|
||||
DEException.throwException("link token格式错误!");
|
||||
}
|
||||
|
||||
Object shareSecretManage = CommonBeanFactory.getBean("shareSecretManage");
|
||||
Method getSecretMethod = DeReflectUtil.findMethod(shareSecretManage.getClass(), "getSecret");
|
||||
Object pwdObj = ReflectionUtils.invokeMethod(getSecretMethod, shareSecretManage, resourceId, userId);
|
||||
String linkSecret = pwdObj.toString();
|
||||
|
||||
Algorithm algorithm = Algorithm.HMAC256(linkSecret);
|
||||
Verification verification = JWT.require(algorithm);
|
||||
JWTVerifier verifier = verification.build();
|
||||
DecodedJWT decode = JWT.decode(linkToken);
|
||||
algorithm.verify(decode);
|
||||
verifier.verify(linkToken);
|
||||
|
||||
UserUtils.setUserInfo(new TokenUserBO(userId, oid));
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user