diff --git a/bonus-admin/src/main/java/com/bonus/web/controller/archive/FileManagementController.java b/bonus-admin/src/main/java/com/bonus/web/controller/archive/FileManagementController.java index 48a3b6a..8f3b42d 100644 --- a/bonus-admin/src/main/java/com/bonus/web/controller/archive/FileManagementController.java +++ b/bonus-admin/src/main/java/com/bonus/web/controller/archive/FileManagementController.java @@ -30,6 +30,7 @@ import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -370,22 +371,76 @@ public class FileManagementController extends BaseController { return R.fail("文件未找到"); } - String filePath = uploadDir + record.getFilePath(); - String fileName = record.getFileName(); + // 直接使用字符串处理构建安全路径 + String safeFullPath = buildSecureFullPath(uploadDir, record.getFilePath()); + if (safeFullPath == null) { + return R.fail("无效的文件路径"); + } - Path path = Paths.get(filePath); + File file = new File(safeFullPath); + if (!file.exists() || !file.isFile()) { + return R.fail("文件未找到"); + } - // 2. 读取文件为字节数组 - byte[] fileBytes = Files.readAllBytes(path); + try { + byte[] fileBytes = Files.readAllBytes(file.toPath()); + String base64String = Base64.getEncoder().encodeToString(fileBytes); - // 3. 转为 Base64 编码字符串 - String base64String = Base64.getEncoder().encodeToString(fileBytes); + response.put("fileName", record.getFileName()); + response.put("suffix_name", record.getSuffixName()); + response.put("fileBase64", base64String); + return R.ok(response); + } catch (IOException e) { + return R.fail("文件读取失败"); + } + } - // 4. 设置响应数据 - response.put("fileName", fileName); - response.put("suffix_name", record.getSuffixName()); - // Base64 内容(可直接用于前端) - response.put("fileBase64", base64String); - return R.ok(response); + /** + * 构建安全的完整文件路径 + */ + private String buildSecureFullPath(String baseDir, String filePath) { + if (StringUtils.isBlank(filePath)) { + return null; + } + + // 统一路径分隔符 + String unifiedPath = filePath.replace('\\', '/'); + + // 移除开头的斜杠 + unifiedPath = unifiedPath.replaceAll("^/+", ""); + + // 检查路径遍历 + if (unifiedPath.contains("../") || unifiedPath.contains("..\\")) { + return null; + } + + // 检查绝对路径 + if (unifiedPath.matches("^[a-zA-Z]:/.*") || unifiedPath.startsWith("/")) { + return null; + } + + // 构建完整路径 + String fullPath; + if (baseDir.endsWith(File.separator)) { + fullPath = baseDir + unifiedPath; + } else { + fullPath = baseDir + File.separator + unifiedPath; + } + + // 使用File的getCanonicalPath进行最终验证 + try { + File canonicalFile = new File(fullPath); + String canonicalPath = canonicalFile.getCanonicalPath(); + + // 验证是否仍在基础目录内 + String canonicalBaseDir = new File(baseDir).getCanonicalPath(); + if (!canonicalPath.startsWith(canonicalBaseDir)) { + return null; + } + + return canonicalPath; + } catch (IOException e) { + return null; + } } } diff --git a/bonus-common/src/main/java/com/bonus/common/utils/encryption/Sm4Utils.java b/bonus-common/src/main/java/com/bonus/common/utils/encryption/Sm4Utils.java index 7b4f648..61fbffd 100644 --- a/bonus-common/src/main/java/com/bonus/common/utils/encryption/Sm4Utils.java +++ b/bonus-common/src/main/java/com/bonus/common/utils/encryption/Sm4Utils.java @@ -4,17 +4,42 @@ import cn.hutool.core.util.HexUtil; import cn.hutool.crypto.Mode; import cn.hutool.crypto.Padding; import cn.hutool.crypto.symmetric.SM4; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; /** * @author bonus */ +@Component public class Sm4Utils { /** * 必须是16字节 */ - private static final String KEY = "78d1295afa99449b99d6f83820e6965c"; + @Value("${Sm4.KEY}") + private String key; - private static final String IV = "f555adf6c01d0ab0761e626a2dae34a2"; + @Value("${Sm4.IV}") + private String iv; + + private static String KEY; + private static String IV; + + @PostConstruct + public void init() { + KEY = this.key; + IV = this.iv; + } + + // 静态方法供外部使用 + public static String getKey() { + return KEY; + } + + public static String getIv() { + return IV; + } /** * 加密数据,使用固定盐 * @@ -23,7 +48,9 @@ public class Sm4Utils { */ public static String encrypt(String plainText) { try { - SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(KEY),HexUtil.decodeHex(IV)); + SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(getKey()),HexUtil.decodeHex(getIv())); + System.out.println("key:"+getKey()); + System.out.println("iv:"+getIv()); // 加密带盐的明文 byte[] encryptedData = sm4.encrypt(plainText); // 返回带盐的加密结果(Hex编码) @@ -43,7 +70,7 @@ public class Sm4Utils { public static String decrypt(String cipherText) { try { // 初始化SM4解密工具 - SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(KEY),HexUtil.decodeHex(IV)); + SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(getKey()),HexUtil.decodeHex(getIv())); // 解密数据 byte[] decryptedData = sm4.decrypt(cipherText); return new String(decryptedData); @@ -53,7 +80,7 @@ public class Sm4Utils { } // 测试方法,演示加密和解密过程 - public static void main(String[] args) { +/* public static void main(String[] args) { String plainText = "15398187429"; System.out.println("原文: " + plainText); @@ -64,5 +91,5 @@ public class Sm4Utils { // 解密密文 String decryptedText = Sm4Utils.decrypt(plainText); System.out.println("解密后: " + decryptedText); - } + }*/ } diff --git a/bonus-common/src/main/java/com/bonus/common/utils/http/HttpUtils.java b/bonus-common/src/main/java/com/bonus/common/utils/http/HttpUtils.java index eb53c55..5c59ebc 100644 --- a/bonus-common/src/main/java/com/bonus/common/utils/http/HttpUtils.java +++ b/bonus-common/src/main/java/com/bonus/common/utils/http/HttpUtils.java @@ -25,7 +25,7 @@ import org.springframework.http.MediaType; /** * 通用http发送方法 - * + * * @author bonus */ public class HttpUtils @@ -132,7 +132,7 @@ public class HttpUtils /** * 向指定 URL 发送POST方法的请求 - * + * * @param url 发送请求的 URL * @param param 请求参数 * @param contentType 内容类型 @@ -215,7 +215,8 @@ public class HttpUtils try { log.info("sendSSLPost - {}", urlNameString); - SSLContext sc = SSLContext.getInstance("SSL"); +// SSLContext sc = SSLContext.getInstance("SSL"); + SSLContext sc = SSLContext.getInstance("TLSv1.2"); sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); URL console = new URL(urlNameString); HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); @@ -228,7 +229,7 @@ public class HttpUtils conn.setDoInput(true); conn.setSSLSocketFactory(sc.getSocketFactory()); - conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); + conn.setHostnameVerifier(new SecureHostnameVerifier()); conn.connect(); InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); @@ -282,12 +283,18 @@ public class HttpUtils } } - private static class TrustAnyHostnameVerifier implements HostnameVerifier - { + public static class SecureHostnameVerifier implements HostnameVerifier { + private final HostnameVerifier defaultVerifier; + + public SecureHostnameVerifier() { + // 使用 JVM 默认的主机名验证器 + this.defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); + } + @Override - public boolean verify(String hostname, SSLSession session) - { - return true; + public boolean verify(String hostname, SSLSession session) { + // 使用标准的主机名验证 + return defaultVerifier.verify(hostname, session); } } -} \ No newline at end of file +} diff --git a/bonus-framework/src/main/java/com/bonus/framework/filter/RequestCoverFilter.java b/bonus-framework/src/main/java/com/bonus/framework/filter/RequestCoverFilter.java index e8267cc..c05f9e9 100644 --- a/bonus-framework/src/main/java/com/bonus/framework/filter/RequestCoverFilter.java +++ b/bonus-framework/src/main/java/com/bonus/framework/filter/RequestCoverFilter.java @@ -159,7 +159,6 @@ public class RequestCoverFilter implements Filter { if (integrality) { String[] parts = requestBody.split("\\|"); if (parts.length != 2) { - log.error("解密后的请求体格式不正确: {}", requestBody); throw new CaptchaException("请求参数不正确"); } integrityVerification(parts[1], parts[0]); @@ -176,7 +175,6 @@ public class RequestCoverFilter implements Filter { chain.doFilter(wrappedRequest, response); } catch (Exception e) { - log.error("处理请求体时发生错误: {}", e.getMessage(), e); throw new ServletException("请求处理失败", e); } } @@ -235,7 +233,6 @@ public class RequestCoverFilter implements Filter { if (integrality) { String[] parts = query.split("\\|"); if (parts.length != 2) { - log.error("解密后的参数格式不正确: {}", query); throw new CaptchaException("请求参数不正确"); } integrityVerification(parts[1], parts[0]); @@ -250,7 +247,6 @@ public class RequestCoverFilter implements Filter { return new QueryStringRequestWrapper(request, query); } catch (Exception e) { - log.error("解密查询参数时发生错误: {}", e.getMessage(), e); throw new CaptchaException("请求参数不正确"); } } @@ -488,7 +484,6 @@ public class RequestCoverFilter implements Filter { if (integrality) { String[] parts = decryptedParams.split("\\|"); if (parts.length != 2) { - log.error("解密后的参数格式不正确: {}", decryptedParams); throw new CaptchaException("请求参数不正确"); } integrityVerification(parts[1], parts[0]); @@ -505,7 +500,6 @@ public class RequestCoverFilter implements Filter { } } catch (Exception e) { - log.error("处理 multipart params 参数时发生错误: {}", e.getMessage(), e); throw new CaptchaException("请求参数不正确"); } } @@ -520,8 +514,8 @@ public class RequestCoverFilter implements Filter { throw new CaptchaException("请求参数不正确"); } String calculatedHash = Sm3Util.encrypt(data); - log.info("计算出的哈希值: {}", calculatedHash); - log.info("提供的哈希值: {}", providedHmac); +// log.info("计算出的哈希值: {}", calculatedHash); +// log.info("提供的哈希值: {}", providedHmac); if (!calculatedHash.equals(providedHmac)) { log.error("参数完整性校验失败"); throw new CaptchaException("请求参数不正确"); @@ -606,4 +600,4 @@ public class RequestCoverFilter implements Filter { } return SystemConfigStatus; } -} \ No newline at end of file +} diff --git a/bonus-generator/src/main/java/com/bonus/generator/controller/GenController.java b/bonus-generator/src/main/java/com/bonus/generator/controller/GenController.java index 68c3991..e2595ca 100644 --- a/bonus-generator/src/main/java/com/bonus/generator/controller/GenController.java +++ b/bonus-generator/src/main/java/com/bonus/generator/controller/GenController.java @@ -194,7 +194,7 @@ public class GenController extends BaseController { /** * 生成代码(自定义路径) */ - @RequiresPermissions("tool:gen:code") +/* @RequiresPermissions("tool:gen:code") @Log(title = "代码生成", businessType = BusinessType.GENCODE) @GetMapping("/genCode/{tableName}") public AjaxResult genCode(@PathVariable("tableName") String tableName) { @@ -203,7 +203,7 @@ public class GenController extends BaseController { } genTableService.generatorCode(tableName); return success(); - } + }*/ /** * 同步数据库 diff --git a/bonus-generator/src/main/java/com/bonus/generator/mapper/GenTableMapper.java b/bonus-generator/src/main/java/com/bonus/generator/mapper/GenTableMapper.java index 766fbf0..cd0fb51 100644 --- a/bonus-generator/src/main/java/com/bonus/generator/mapper/GenTableMapper.java +++ b/bonus-generator/src/main/java/com/bonus/generator/mapper/GenTableMapper.java @@ -2,17 +2,18 @@ package com.bonus.generator.mapper; import java.util.List; import com.bonus.generator.domain.GenTable; +import org.apache.ibatis.annotations.Param; /** * 业务 数据层 - * + * * @author bonus */ public interface GenTableMapper { /** * 查询业务列表 - * + * * @param genTable 业务信息 * @return 业务集合 */ @@ -20,7 +21,7 @@ public interface GenTableMapper /** * 查询据库列表 - * + * * @param genTable 业务信息 * @return 数据库表集合 */ @@ -28,7 +29,7 @@ public interface GenTableMapper /** * 查询据库列表 - * + * * @param tableNames 表名称组 * @return 数据库表集合 */ @@ -36,14 +37,14 @@ public interface GenTableMapper /** * 查询所有表信息 - * + * * @return 表信息集合 */ public List selectGenTableAll(); /** * 查询表ID业务信息 - * + * * @param id 业务ID * @return 业务信息 */ @@ -51,7 +52,7 @@ public interface GenTableMapper /** * 查询表名称业务信息 - * + * * @param tableName 表名称 * @return 业务信息 */ @@ -59,7 +60,7 @@ public interface GenTableMapper /** * 新增业务 - * + * * @param genTable 业务信息 * @return 结果 */ @@ -67,7 +68,7 @@ public interface GenTableMapper /** * 修改业务 - * + * * @param genTable 业务信息 * @return 结果 */ @@ -75,7 +76,7 @@ public interface GenTableMapper /** * 批量删除业务 - * + * * @param ids 需要删除的数据ID * @return 结果 */ @@ -87,5 +88,5 @@ public interface GenTableMapper * @param sql 表结构 * @return 结果 */ - public int createTable(String sql); + public int createTable(@Param("sql") String sql); } diff --git a/bonus-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/bonus-generator/src/main/resources/mapper/generator/GenTableMapper.xml index 8695407..cde3d92 100644 --- a/bonus-generator/src/main/resources/mapper/generator/GenTableMapper.xml +++ b/bonus-generator/src/main/resources/mapper/generator/GenTableMapper.xml @@ -28,7 +28,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + @@ -53,11 +53,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, tpl_web_type, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from da_ky_gen_table - + - + - + - + - + - + - + insert into da_ky_gen_table ( table_name, @@ -170,11 +170,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" sysdate() ) - + - ${sql} + #{sql} - + update da_ky_gen_table @@ -199,7 +199,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where table_id = #{tableId} - + delete from da_ky_gen_table where table_id in @@ -207,4 +207,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - \ No newline at end of file + diff --git a/bonus-system/src/main/resources/mapper/system/SysDeptMapper.xml b/bonus-system/src/main/resources/mapper/system/SysDeptMapper.xml index d6eeae2..660735e 100644 --- a/bonus-system/src/main/resources/mapper/system/SysDeptMapper.xml +++ b/bonus-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -42,8 +42,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND status = #{status} - - ${params.dataScope} order by d.parent_id, d.order_num diff --git a/bonus-system/src/main/resources/mapper/system/SysRoleMapper.xml b/bonus-system/src/main/resources/mapper/system/SysRoleMapper.xml index 5f807f1..d340af0 100644 --- a/bonus-system/src/main/resources/mapper/system/SysRoleMapper.xml +++ b/bonus-system/src/main/resources/mapper/system/SysRoleMapper.xml @@ -51,8 +51,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and date_format(r.create_time,'%Y%m%d') <= date_format(#{params.endTime},'%Y%m%d') - - ${params.dataScope} order by r.role_sort diff --git a/bonus-system/src/main/resources/mapper/system/SysUserMapper.xml b/bonus-system/src/main/resources/mapper/system/SysUserMapper.xml index 0471064..f0b88d0 100644 --- a/bonus-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/bonus-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -91,8 +91,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM da_ky_sys_dept t WHERE find_in_set(#{deptId}, ancestors) )) - - ${params.dataScope}