From 3efda9d29c0df4300d43bb7874638e03060c3e2d Mon Sep 17 00:00:00 2001 From: tjlygdx Date: Wed, 13 May 2026 17:28:30 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E3=80=90=E6=BC=8F=E6=B4=9E=E3=80=91?= =?UTF-8?q?=E4=BF=AE=E5=A4=8Dunauthorized=20command=20execution=20vulnerab?= =?UTF-8?q?ility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/SubstituleLoginServer.java | 4 +- .../auth/config/SubstituleLoginConfig.java | 96 +++++++++++++++---- .../auth/filter/CommunityTokenFilter.java | 3 +- 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/core/core-backend/src/main/java/io/dataease/substitute/permissions/login/SubstituleLoginServer.java b/core/core-backend/src/main/java/io/dataease/substitute/permissions/login/SubstituleLoginServer.java index cc6de17d76..e6c5485abc 100644 --- a/core/core-backend/src/main/java/io/dataease/substitute/permissions/login/SubstituleLoginServer.java +++ b/core/core-backend/src/main/java/io/dataease/substitute/permissions/login/SubstituleLoginServer.java @@ -10,7 +10,6 @@ import io.dataease.auth.vo.TokenVO; import io.dataease.exception.DEException; import io.dataease.i18n.Translator; import io.dataease.utils.LogUtil; -import io.dataease.utils.Md5Utils; import io.dataease.utils.RsaUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -43,8 +42,7 @@ public class SubstituleLoginServer { TokenUserBO tokenUserBO = new TokenUserBO(); tokenUserBO.setUserId(1L); tokenUserBO.setDefaultOid(1L); - String md5Pwd = Md5Utils.md5(pwd); - return generate(tokenUserBO, md5Pwd); + return generate(tokenUserBO, SubstituleLoginConfig.getTokenSecret()); } diff --git a/sdk/common/src/main/java/io/dataease/auth/config/SubstituleLoginConfig.java b/sdk/common/src/main/java/io/dataease/auth/config/SubstituleLoginConfig.java index ee742cb955..a84e4b97a7 100644 --- a/sdk/common/src/main/java/io/dataease/auth/config/SubstituleLoginConfig.java +++ b/sdk/common/src/main/java/io/dataease/auth/config/SubstituleLoginConfig.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.dataease.utils.CommonBeanFactory; import io.dataease.utils.LogUtil; import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -16,16 +17,21 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.UUID; @ConditionalOnMissingBean(name = "loginServer") @Configuration public class SubstituleLoginConfig { + private static final String PWD_KEY = "pwd"; + private static final String TOKEN_SECRET_KEY = "tokenSecret"; @Value("${dataease.path.substitule:classpath:substitule.json}") private String jsonFilePath; private static String pwd; + private static String tokenSecret; + private static boolean ready = false; @@ -34,39 +40,91 @@ public class SubstituleLoginConfig { public Map substituleLoginData(ResourceLoader resourceLoader) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); File jsonFile = new File(jsonFilePath); - if (!jsonFile.exists()) { - pwd = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.default-pwd", "DataEase@123456"); - modifyPwd(pwd); + Map result = jsonFile.exists() ? objectMapper.readValue(jsonFile, Map.class) : new HashMap<>(); + boolean updated = false; + Environment environment = CommonBeanFactory.getBean(Environment.class); + String configuredPwd = environment == null ? null : environment.getProperty("dataease.default-pwd"); + pwd = readString(result, PWD_KEY); + if (StringUtils.isBlank(pwd)) { + pwd = StringUtils.isNotBlank(configuredPwd) ? configuredPwd : generatePwd(); + result.put(PWD_KEY, pwd); + updated = true; + if (StringUtils.isBlank(configuredPwd)) { + LogUtil.info("Generated substitute admin password in " + jsonFilePath + ". Please keep the file secure."); + } } - return objectMapper.readValue(jsonFile, Map.class); + tokenSecret = readString(result, TOKEN_SECRET_KEY); + if (StringUtils.isBlank(tokenSecret)) { + tokenSecret = generateSecret(); + result.put(TOKEN_SECRET_KEY, tokenSecret); + updated = true; + } + if (updated) { + writeConfig(jsonFile, result); + } + return result; } public static String getPwd() { - if (!ready) { - ready = true; - Object substituleLoginDataObject = CommonBeanFactory.getBean("substituleLoginData"); - if (substituleLoginDataObject != null) { - Map substituleLoginData = (Map) substituleLoginDataObject; - if (ObjectUtils.isNotEmpty(substituleLoginData.get("pwd"))) { - pwd = substituleLoginData.get("pwd").toString(); - return substituleLoginData.get("pwd").toString(); - } + loadSubstituleLoginData(); + return pwd; + } + + public static String getTokenSecret() { + loadSubstituleLoginData(); + return tokenSecret; + } + + private static synchronized void loadSubstituleLoginData() { + if (ready) { + return; + } + ready = true; + Object substituleLoginDataObject = CommonBeanFactory.getBean("substituleLoginData"); + if (substituleLoginDataObject != null) { + Map substituleLoginData = (Map) substituleLoginDataObject; + String configuredPwd = readString(substituleLoginData, PWD_KEY); + if (StringUtils.isNotBlank(configuredPwd)) { + pwd = configuredPwd; + } + String configuredTokenSecret = readString(substituleLoginData, TOKEN_SECRET_KEY); + if (StringUtils.isNotBlank(configuredTokenSecret)) { + tokenSecret = configuredTokenSecret; } } - return pwd; } public void modifyPwd(String pwd) { File file = new File(jsonFilePath); Map myObject = new HashMap<>(); - myObject.put("pwd", pwd); + myObject.put(PWD_KEY, pwd); + myObject.put(TOKEN_SECRET_KEY, ObjectUtils.isNotEmpty(tokenSecret) ? tokenSecret : generateSecret()); SubstituleLoginConfig.pwd = pwd; - ObjectMapper mapper = new ObjectMapper(); - try (FileOutputStream fos = new FileOutputStream(file)) { - // 将对象写入文件 - mapper.writeValue(fos, myObject); + SubstituleLoginConfig.tokenSecret = myObject.get(TOKEN_SECRET_KEY); + try { + writeConfig(file, myObject); } catch (IOException e) { LogUtil.error(e.getCause(), new Throwable(e)); } } + + private static void writeConfig(File file, Map config) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + try (FileOutputStream fos = new FileOutputStream(file)) { + mapper.writeValue(fos, config); + } + } + + private static String readString(Map config, String key) { + Object value = config.get(key); + return ObjectUtils.isEmpty(value) ? null : value.toString(); + } + + private static String generatePwd() { + return "DE-" + UUID.randomUUID().toString().replace("-", ""); + } + + private static String generateSecret() { + return UUID.randomUUID().toString().replace("-", "") + UUID.randomUUID().toString().replace("-", ""); + } } diff --git a/sdk/common/src/main/java/io/dataease/auth/filter/CommunityTokenFilter.java b/sdk/common/src/main/java/io/dataease/auth/filter/CommunityTokenFilter.java index bde3c23e13..f647f8758b 100644 --- a/sdk/common/src/main/java/io/dataease/auth/filter/CommunityTokenFilter.java +++ b/sdk/common/src/main/java/io/dataease/auth/filter/CommunityTokenFilter.java @@ -37,8 +37,7 @@ public class CommunityTokenFilter implements Filter { if (StringUtils.isNotBlank(token) && ObjectUtils.isNotEmpty(userBO = AuthUtils.getUser()) && ObjectUtils.isNotEmpty(userId = userBO.getUserId()) && !LicenseUtil.licenseValid()) { String secret = null; if (ObjectUtils.isEmpty(CommonBeanFactory.getBean("loginServer"))) { - String pwd = SubstituleLoginConfig.getPwd(); - secret = Md5Utils.md5(pwd); + secret = SubstituleLoginConfig.getTokenSecret(); } else { Object apisixCacheManage = CommonBeanFactory.getBean("apisixCacheManage"); Method method = DeReflectUtil.findMethod(apisixCacheManage.getClass(), "userCacheBO");