maku-boot 安全审计报告
审计对象:
maku-bootv5.0.0(Spring Boot 4.0.6 / Java 17 / MyBatis-Plus 3.5.16 / Spring Security)
审计日期:2026-08-13
审计方式:静态源码审计(人工验证 + 多路并行扫描),未做动态利用验证
报告目录:本文档为完整审计报告
一、执行摘要
maku-boot 是一个低代码/快速开发平台,认证体系为 Spring Security + Bearer Token(存 Redis),方法级鉴权依赖 @PreAuthorize。整体框架安全基线尚可(mapper 层基本全参数化、XSS 过滤开启、登录密码 SM2 传输加密),但存在若干高危/严重缺陷,核心问题集中在:
- 文件上传可路径穿越 → 任意文件写入,且无扩展名白名单、
/upload/**免认证静态返回 → 可托管恶意文件 / 存储型 XSS / 潜在 RCE; - 字典模块存储型 SQL 注入(
@Select("${sql}")),且触发接口/sys/dict/type/all缺少鉴权; - 分页排序字段 ORDER BY 注入,影响全平台所有分页接口;
- 大量
page/list端点缺少@PreAuthorize,导致任何已登录用户即可枚举用户、读取操作日志/登录日志、读取短信/邮件配置中的云厂商 AccessKey/SecretKey/邮箱密码、并可通过公开的邮件发送接口中继发信; - SM2 私钥硬编码在源码、密码使用无盐 SM3 存储、默认口令
admin/admin、生产配置硬编码123456等弱凭据; - Quartz 定时任务可反射调用任意 @Service Bean 的任意单 String 参数方法(无方法白名单)。
风险统计:严重 1、高危 8、中危 7、低危 6(详见下文)。
| 风险等级 | 数量 | 代表问题 |
|---|---|---|
| 🔴 Critical | 1 | 上传路径穿越 → 任意文件写 |
| 🟠 High | 8 | 存储型 SQL 注入 / 越权访问 / 密钥泄露 / 邮件中继 / 用户枚举 / 凭据问题 |
| 🟡 Medium | 7 | SSRF / 反序列化配置 / OAuth 缺陷 / CORS / Quartz 反射 |
| 🟢 Low | 6 | WebSocket 越权 / XSS 空隙 / actuator 配置等 |
所有漏洞均已人工核实到
文件:行号级;未做动态利用(PoC 均为静态推演)。
二、风险等级分布
| # | 漏洞 | 等级 | 位置 | 影响 |
|---|---|---|---|---|
| 1 | 上传文件名路径穿越 → 任意文件写 | 🔴 Critical | SysFileUploadController / StorageService / LocalStorageService |
服务器文件写入,RCE 候选 |
| 2 | 字典模块存储型 SQL 注入 | 🟠 High | SysDictDataDao / SysDictTypeController.all |
任意 SQL 执行,拖库 |
| 3 | 分页 ORDER BY 注入 | 🟠 High | BaseServiceImpl.getPage / Query.order |
全平台分页接口报错/时间盲注 |
| 4 | 邮件配置密钥泄露 + 无鉴权邮件中继 | 🟠 High | SysMailConfigController.list/send |
云密钥泄露、任意发信 |
| 5 | 短信配置密钥泄露 | 🟠 High | SysSmsConfigController.list |
AccessKey/SecretKey 泄露 |
| 6 | 用户枚举 + 数据越权(数据权限被注释) | 🟠 High | SysUserController.page / SysUserServiceImpl |
全量用户信息泄露 |
| 7 | 操作/登录日志越权读取 | 🟠 High | SysLogOperateController.page / SysLogLoginController.page |
密码哈希、密钥、IP 泄露 |
| 8 | SM2 私钥硬编码 + 无盐 SM3 密码 | 🟠 High | Sm2Util / Sm3PasswordEncoder |
传输密码可解密、口令可离线破解 |
| 9 | 硬编码弱凭据(默认口令/生产配置) | 🟠 High | maku.sql / application-prod.yml |
默认口令、DB/Redis/MQTT 弱凭据 |
| 10 | Quartz 任意 Bean 方法反射调用 | 🟡 Medium | AbstractScheduleJob / ScheduleJobController |
任意单参方法调用 |
| 11 | 配置驱动型 SSRF(华为短信) | 🟡 Medium | HuaweiSmsStrategy |
公开接口触发内网请求 |
| 12 | 第三方登录 OAuth 缺陷 | 🟡 Medium | SysThirdLoginController / third_login.ftlh |
code/state 泄露、open redirect |
| 13 | Redis 反序列化开启任意多态 | 🟡 Medium | RedisConfig |
反序列化 RCE 候选 |
| 14 | CORS 通配 + 凭证 | 🟡 Medium | CorsConfig / SecurityAuthenticationEntryPoint |
跨域读取放大 |
| 15 | Refresh Token 不轮换 | 🟡 Medium | SysUserTokenServiceImpl.refreshToken |
token 泄露后长期有效 |
| 16 | Token 可放 URL query 参数 | 🟡 Medium | TokenUtils.getAccessToken |
token 进入日志/Referer |
| 17 | WebSocket 无方法级鉴权 + Origin 通配 | 🟢 Low | SendMessageController / WebSocketConfig |
任意用户给任意人推消息 |
| 18 | Excel 导入绕过 XSS 过滤 → 存储型 XSS | 🟢 Low-Med | SysUserServiceImpl.importByExcel |
用户字段 XSS |
| 19 | 操作日志 User-Agent 存储型 XSS | 🟢 Low | OperateLogAspect |
管理端日志页 XSS |
| 20 | 机构/岗位/字典只读接口无鉴权 | 🟢 Low | SysOrgController 等 |
组织架构枚举 |
| 21 | actuator 免认证白名单残留 | 🟢 Low | auth.yml |
配置遗留,潜在暴露 |
| 22 | 404 处理反射 resourcePath | 🟢 Low | ServerExceptionHandler |
反射 XSS 候选 |
三、详细发现
🔴 3.1 【Critical】上传文件名路径穿越 → 任意文件写入
位置
maku-boot-system/src/main/java/net/maku/system/controller/SysFileUploadController.java:34,40-42,56,62-64(两个上传端点,均无@PreAuthorize)maku-boot-system/src/main/java/net/maku/storage/service/StorageService.java:26-35(getNewFileName)、:60-62(getPath)maku-boot-system/src/main/java/net/maku/storage/service/LocalStorageService.java:35-43
问题描述
上传文件名取自 file.getOriginalFilename()(客户端 Content-Disposition: filename= 完全可控),未经任何清洗即用于拼接存储路径。getNewFileName 使用 hutool FileNameUtil.getPrefix/getSuffix 生成 prefix_<秒时间戳>.<suffix>,而 hutool 的 getPrefix 保留 ../、/、\ 段(仅按最后一个 . 截断)。
// StorageService.java:28-34
String prefix = FileNameUtil.getPrefix(fileName); // "../../x" → 保留穿越段
String suffix = FileNameUtil.getSuffix(fileName);
return prefix + "_" + time + "." + suffix;
// LocalStorageService.java:35-43
File file = new File(properties.getLocal().getPath() + File.separator + path);
File parent = file.getParentFile();
if (parent != null && !parent.mkdirs() && !parent.isDirectory()) { ... } // 自动创建任意目录
FileCopyUtils.copy(inputStream, Files.newOutputStream(file.toPath())); // 任意路径写
利用场景
- 上传
filename="../../../../etc/cron.d/evil"→ 在 Linux 部署下写入/etc/cron.d/(若运行于 root)或任意应用目录; - 上传
filename="../../xxx.jsp"(若部署启用了 JSP Servlet)或.html/.svg→ 写入后可被 Web 容器执行/访问; - 即使无法写出上传根目录,
.html/.svg也能经/upload/**(免认证静态资源)原样返回 → 存储型 XSS(见 3.2)。
修复建议
- 上传文件名一律用服务端生成(如 UUID),不信任客户端文件名;
- 对文件名做
Path.normalize()+ 白名单校验,拒绝../、/、\、空字节; - 增加扩展名/Content-Type 白名单(仅允许图片/文档类);
- 上传接口加
@PreAuthorize。
🟠 3.2 【High】存储型 SQL 注入 — 字典模块 ${sql}
位置
maku-boot-system/src/main/java/net/maku/system/dao/SysDictDataDao.java:21-22@Select("${sql}") List<SysDictVO.DictData> getListForSql(@Param("sql") String sql);- 调用方
maku-boot-system/.../service/impl/SysDictTypeServiceImpl.java:135,163-167,203(dictSql原样拼接执行) - 存储源
maku-boot-system/.../vo/SysDictTypeVO.java:51-54(dictSource+dictSql,无任何校验) - 触发入口
SysDictTypeController.java:GET /sys/dict/type/all(L104-110)— 无@PreAuthorize,遍历执行所有dictSource==SQL的 dictSql;GET /sys/dict/type/list/sql?id=(L54-63)— 需sys:dict:page;refreshTransCache(L112-118)— 需sys:dict:refreshTransCache。
问题描述
dictSql 通过 /sys/dict/type 的 save/update 入库(sys:dict:save/update 权限),无任何格式/关键字校验;执行时用 ${sql} 字符串直拼。/sys/dict/type/all 又缺少鉴权,任意已登录用户即可触发全量执行。
利用场景
- 拥有
sys:dict:save/update的普通运营人员写入dictSql = select updatexml(1,concat(0x7e,user()),1)→ 拖取任意数据; - 任意已登录用户(哪怕只有监控权限)访问
/sys/dict/type/all触发执行; - 可利用
load_file、时间盲注、联合查询等方式读取全库,执行权限为应用 DB 账号。
修复建议
- 禁止
${sql}动态执行;dictSql 改为白名单化的有限语法解析或改用参数化查询; - save/update 对
dictSql做关键字(union/select into/update/delete/drop/load_file 等)与长度校验; /sys/dict/type/all补@PreAuthorize。
🟠 3.3 【High】ORDER BY 排序字段注入(全平台分页)
位置
maku-framework/src/main/java/net/maku/framework/mybatis/service/impl/BaseServiceImpl.java:34-47if (StringUtils.isNotBlank(query.getOrder())) { if (query.isAsc()) { return page.addOrder(OrderItem.asc(query.getOrder())); } else { return page.addOrder(OrderItem.desc(query.getOrder())); } }- 参数来源
maku-framework/.../common/query/Query.java:27-31(String order;直接绑定 HTTP 参数,无白名单) - 影响范围:所有继承
Query的分页接口(SysUser、SysDict、IotDevice、MemberUser、ScheduleJob、日志等 19+ 个 Query 子类)
问题描述
MyBatis-Plus 分页插件将 OrderItem 的列名按 ORDER BY ${column} ASC/DESC 原样拼接,列名不做参数化也不做校验。?order=... 直接可达。
利用场景
GET /sys/user/page?order=(select extractvalue(1,concat(0x7e,user())))&asc=false→ 报错注入;?order=1,(select sleep(5))→ 时间盲注;- 可读取任意表数据(在已认证的前提下)。
/sys/user/page本身还无鉴权,攻击面被进一步放大。
修复建议
- 对
order做字段白名单校验(映射到实体字段集)或对非法字符做过滤; - 全局拦截器对 OrderItem 列名做正则校验。
🟠 3.4 【High】邮件配置密钥泄露 + 无鉴权邮件中继
位置
SysMailConfigController.java:53-59—GET /sys/mail/config/list无@PreAuthorize,返回全部配置;SysMailConfigController.java:79-127—POST /sys/mail/config/send无@PreAuthorize,任意已登录用户可发信;SysMailConfigVO.java:39-52— VO 明文包含mailPass、accessKey、secretKey。
问题描述
list 接口对任意已登录用户返回邮件 SMTP 密码、阿里云 AccessKey/SecretKey;send 接口允许用该配置向任意收件人发送任意内容(支持 HTML),无权限限制。
利用场景
- 低权限用户
GET /sys/mail/config/list→ 窃取 SMTP 密码/云密钥; POST /sys/mail/config/send→ 借用企业邮箱账号群发钓鱼邮件/垃圾邮件(邮件中继),也可被用于身份冒充。
修复建议
- VO 序列化时对
mailPass/accessKey/secretKey脱敏(返回***); list/send补@PreAuthorize("hasAuthority('sys:mail:config')");- 发送目标、频率做限制。
🟠 3.5 【High】短信配置密钥泄露
位置
SysSmsConfigController.java:53-59—GET /sys/sms/config/list无@PreAuthorize;SysSmsConfigVO.java:46-50— 明文包含accessKey、secretKey(及url接入地址)。
问题描述
任意已登录用户可读取所有短信平台的云 AccessKey/SecretKey(阿里/腾讯/华为/七牛)。
利用场景
- 窃取云短信密钥 → 批量下发短信(资金损失/骚扰),或利用同一密钥访问云账号其他资源。
修复建议
- 同 3.4:VO 脱敏 + 补鉴权。
🟠 3.6 【High】用户枚举 + 数据越权(数据权限被注释)
位置
SysUserController.java:48-54—GET /sys/user/page无@PreAuthorize;SysUserServiceImpl.java:54-67,69-84—getParams中// params.put(Constant.DATA_SCOPE, getDataScope("t1", null));(L76)数据权限被注释掉;SysUserDao.xml:7—getList仅过滤super_admin = 0 and deleted = 0;- 另:
SysUserController.nameList(L185-191)、orgUserList(L193-199)均无鉴权。
问题描述
/sys/user/page 无需 sys:user:page 权限,且查询不应用数据权限,任意已登录用户可翻页查看全量非超管用户(用户名、手机号、机构、性别、状态)。
利用场景
- 枚举全部用户名/手机号 → 用于撞库、钓鱼、短信轰炸;
- 数据权限形同虚设(注:全库仅
SysOrgServiceImpl.java:42使用了 DATA_SCOPE,其余原生 SQL 分页均无数据过滤)。
修复建议
- 恢复
getParams中的数据权限注入,并审计其它原生 SQL 分页; page/nameList/orgUserList补@PreAuthorize。
🟠 3.7 【High】操作日志 / 登录日志越权读取
位置
SysLogOperateController.java:31-40—GET /sys/log/operate/page无@PreAuthorize;SysLogLoginController.java:33-40—GET /sys/log/login/page无@PreAuthorize;OperateLogAspect.java:110,115— 记录User-Agent与reqParams(入参 DTO 全量 JSON);SysLogOperateVO.java:44(reqParams)、:47(ip)、SysLogLoginVO.java:36(username)。
问题描述
操作日志 reqParams 以 JSON 记录请求入参,包括:sys:user:update 时的密码(SM3 哈希)、sys:mail/config 保存时的 mailPass/secretKey 明文、sys:sms/config 保存时的 secretKey 明文等;登录日志含全量用户名 + IP + 登录成败。两个 page 均无鉴权。
利用场景
- 任意已登录用户拉取操作日志 → 获取其他管理员保存的密钥明文、密码哈希(可离线爆破);
- 拉取登录日志 → 确认哪些用户名/手机号存在。
修复建议
- 日志记录敏感字段脱敏(密码/密钥置
***); page补@PreAuthorize。
🟠 3.8 【High】SM2 私钥硬编码 + 无盐 SM3 密码存储
位置
maku-framework/.../security/crypto/Sm2Util.java:26,30—PUBLIC_KEY/PRIVATE_KEY均硬编码在源码;SysAuthServiceImpl.java:56—Sm2Util.decrypt(login.getPassword())用该私钥解密登录密码;maku-framework/.../security/crypto/Sm3PasswordEncoder.java:15-17,20-22—SmUtil.sm3(raw)无盐。
问题描述
私钥随开源代码公开 → 登录"加密"无任何保密性,等价于明文传输;密码存储为无盐 SM3(可预计算彩虹表、相同密码相同哈希)。
利用场景
- 中间人/抓包拿到 SM2 密文 → 用公开私钥解密出明文口令;
- 数据库泄露 → 直接破解弱口令,多个用户同口令哈希相同。
修复建议
- 密钥改为每次部署生成并置于环境变量/密钥管理(KMS);
- 密码哈希改用带盐慢哈希(BCrypt/SCrypt/PBKDF2),SM3 仅作兼容。
🟠 3.9 【High】硬编码弱凭据(默认口令 / 生产配置)
位置
db/mysql/maku.sql:392— 默认超管admin,密码 SM3 哈希(已验证 =SM3("admin"),即默认口令 admin/admin);db/mysql/maku.sql:502— 飞书client_secret = 5Chz39zvEhZtxSVZz3vLjfQHdkvavQaH;db/mysql/maku.sql:504— 163 邮箱mail_pass = TZNVURLYVBNJUNBB(baba_tv@163.comSMTP 授权码);maku-server/src/main/resources/application-prod.yml:23-25— DBusername: maku / password: 123456;application-prod.yml:26-29— MQTTusername: maku / password: maku;application-prod.yml:7-8— Redis#password:(注释掉,即无认证);dev/test 配置同理。
问题描述
默认管理员 admin/admin 可直接登录;生产配置把数据库/消息队列弱口令与真实云密钥写入代码库;Redis 无密码,若服务绑定到非回环地址即可被远程利用(结合 3.13 反序列化配置进一步升级)。
利用场景
- 部署后未改口令 → 直接 admin 登录;
- 生产数据库/MQTT/Redis 凭据泄露 → 数据失窃;
- 飞书/163 凭据可用于登录对应第三方账号或作为邮件中继。
修复建议
- 移除 SQL 脚本与配置中的真实密钥;首次启动强制改密;
- 生产凭据改用环境变量/配置中心 + 密钥管理;
- Redis/MQTT 启用认证。
🟡 3.10 【Medium】Quartz 定时任务可反射调用任意 @Service Bean 方法
位置
maku-boot-module/maku-module-quartz/.../utils/AbstractScheduleJob.java:44-46Object bean = SpringUtil.getBean(scheduleJob.getBeanName()); Method method = bean.getClass().getDeclaredMethod(scheduleJob.getMethod(), String.class); method.invoke(bean, scheduleJob.getParams());maku-boot-module/maku-module-quartz/.../controller/ScheduleJobController.java:122-128—checkBean仅校验 bean 带@Service,无方法白名单。
问题描述
拥有 schedule:save/update/run 权限的用户可指定任意 @Service Bean 的任意 方法名(String) 并传入参数,由 Quartz 反射调用。
利用场景
- 调用
sendMail(String)/sendSms(String)/sendCode(String)等对外动作 → 伪造外发; - 调用
refreshCache/delete(String)/updateByToken(String)等 → 破坏数据/缓存; - 若有方法链到执行逻辑则升级为 RCE。
修复建议
- 对 beanName+method 做白名单(枚举允许执行的 Service 与方法);
- 参数做长度/内容校验。
🟡 3.11 【Medium】配置驱动型 SSRF(华为短信,公开接口触发)
位置
maku-boot-system/src/main/java/net/maku/sms/HuaweiSmsStrategy.java:65-69—new URL(url).openConnection(),URL 来自 DB 配置smsConfig.getUrl();HuaweiSmsStrategy.java:167-186— 关闭 TLS 校验(trustAllHttpsCertificates()+HostnameVerifier恒真);- 触发入口
SysAuthController.java:52-61—POST /sys/auth/send/code(在auth.yml免认证白名单内)。
问题描述
短信接入 URL 由管理员写入 DB,但 send/code 是公开未授权接口。若配置/被篡改为内网地址(如 http://169.254.169.254/、http://127.0.0.1:*),任何未认证请求即可触发服务端向外建连;且 TLS 校验被关闭,内网请求无告警。
利用场景
- 探测内网端口/读取云元数据(配合返回差异判断);
- 全项目无任何出站域名/IP/协议白名单校验(
IpUtils.internalIp未覆盖169.254.169.254、IPv6 等,且仅用于日志定位,不用于出站校验)。
修复建议
- 对出站 URL 做协议(http/https)+ 内网/回环地址拦截(DNS 解析后二次校验);
- 恢复 TLS 证书与主机名校验;
- 短信验证码接口加频率限制(该接口本身也支持短信轰炸)。
🟡 3.12 【Medium】第三方登录 OAuth 缺陷(code/state 泄露 + open redirect)
位置
SysThirdLoginController.java:50-55—render/{source}(免认证)response.sendRedirect(authorizeUrl)→ open redirect 候选(依赖 DB 配置redirectUri);SysThirdLoginController.java:57-65—callback/{source}(免认证)渲染third_login模板;SysThirdLoginController.java:67-86—bind对请求中的code/state无服务端 state 校验(会话中生成的 state 从未被比对);maku-boot-system/src/main/resources/templates/third_login.ftlh:19—window.opener.postMessage(data, "*")向任意 opener 广播 OAuthcode/state;- 入口
/sys/third/render/**、/sys/third/callback/**、/sys/auth/third均在auth.yml免认证白名单。
问题描述
third_login.ftlh 把 code/state 通过 postMessage(data, "*") 发给任意来源窗口 —— 任意恶意站点作为 opener 即可窃取 OAuth 授权码;bind 不校验 state,存在登录 CSRF/绑定接管风险;render 跳转目标依赖配置,误配即 open redirect。
利用场景
- 诱导受害者打开含恶意 opener 的 callback URL → 窃取 code → 绑定/接管账号;
- 配置被篡改时 open redirect 钓鱼。
修复建议
postMessage指定具体可信 origin,不使用"*";bind增加服务端 state 校验(存 Session/Redis);- callback 页对 code/state 做转义(见 3.19 说明,FreeMarker 默认转义已部分缓解)。
🟡 3.13 【Medium】Redis 反序列化开启任意多态
位置
maku-framework/.../common/config/RedisConfig.java:25-36PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder() .allowIfBaseType(Object.class) // 允许一切类型 .build(); ObjectMapper objectMapper = JsonMapper.builder() .activateDefaultTyping(ptv, DefaultTyping.NON_FINAL) .build();
问题描述
Redis 序列化使用 GenericJacksonJsonRedisSerializer 且 allowIfBaseType(Object.class) + NON_FINAL,任何被序列化的多态对象反序列化时都不限制目标类型。若攻击者能向 Redis 写入恶意 JSON(Redis 无密码 + 网络可达,或经 SSRF 打 Redis),可触发 gadget 链导致 RCE。
利用场景
- Redis 未认证且暴露 → 直接写入恶意序列化数据;
- 配合其他漏洞(SSRF/文件写)向 Redis 注入。
修复建议
- 收紧
allowIfBaseType,仅允许业务基类;或改用不开启类型信息的序列化方案(白名单类型)。
🟡 3.14 【Medium】CORS 通配 + 凭证
位置
maku-framework/.../common/config/CorsConfig.java:22-24—setAllowCredentials(true)+addAllowedOriginPattern("*")+ 全部方法/头;maku-framework/.../security/exception/SecurityAuthenticationEntryPoint.java:25-26— 401 响应反射Origin头 +Allow-Credentials: true。
问题描述
全局 CORS 允许任意来源携带凭证跨域。虽然认证走 Bearer Token(非 Cookie),但该配置放大了任意 XSS/凭证泄露的影响面,且 401 响应无条件反射 Origin 属错误配置。
利用场景
- 与前端 XSS 组合时,恶意站点可读取凭据跨域数据;
- 反射 Origin 用于绕过白名单类 WAF。
修复建议
- CORS 固定为具体可信域名列表;不反射任意 Origin;凭证头仅在可信域名下返回。
🟡 3.15 【Medium】Refresh Token 不轮换 + 可放 URL
位置
SysUserTokenServiceImpl.java:70-102—refreshToken验证后仅换发新 accessToken,refreshToken 本身不轮换(有效 14 天);TokenUtils.java:38-42— token 既从Authorization头取,也接受?access_token=URL 参数。
问题描述
refreshToken 一旦泄露(日志、Referer、缓存),14 天内可无限换取新 accessToken 且不可被换发作废;accessToken 走 URL 参数会进入访问日志/Referer/浏览器历史。
利用场景
- 窃取 refreshToken → 持久劫持会话;
- access_token 出现在 URL → 第三方日志泄露。
修复建议
- refreshToken 每次换发都轮换(旧 token 立即失效);
- 仅从 Header 读取 token,禁止 query 参数。
🟢 3.16 【Low】WebSocket 无方法级鉴权 + Origin 通配
位置
maku-boot-module/maku-module-websocket/.../controller/SendMessageController.java:31-51—POST /ws/message/send无@PreAuthorize,任意已登录用户可给任意userId推送消息;WebSocketConfig.java:27-28—.setAllowedOriginPatterns("*")。
问题描述
任意已登录用户可向任意其他用户推送 WebSocket 消息(伪造通知、定向钓鱼)。握手本身经 Spring Security 过滤器链保护(需有效 token),故不构成未授权连接,但推送端点缺少 ws:message:send 权限控制。
修复建议
- 补
@PreAuthorize;限制 Origin。
🟢 3.17 【Low】Excel 导入绕过 XSS 过滤 → 存储型 XSS 候选
位置
SysUserServiceImpl.java:265-275(importByExcel)→ExcelUtils.readAnalysis原样读单元格入库,multipart 内容不经过XssRequestWrapper/XssFilterJsonDeserializer;XssFilter.java:27-42— JSON 请求放行参数 wrapper;文件内容不在过滤范围。
问题描述
恶意 Excel 中用户姓名/手机号可写 <img src=x onerror=...> 入库,管理端列表回显即存储型 XSS(取决于前端渲染是否使用 v-html;Vue 默认插值转义可缓解,需前端确认)。同路径存在 Excel 公式注入候选(导入再导出)。
修复建议
- 导入字段做 XSS 清洗 + 长度/字符集校验;对
= + - @开头做公式注入防护。
🟢 3.18 【Low】操作日志 User-Agent 存储型 XSS 候选
位置
OperateLogAspect.java:110—log.setUserAgent(request.getHeader(USER_AGENT)),JSON 请求下XssRequestWrapper不生效,UA 原样入库;SysLogOperateVO.java:53(userAgent)经SysLogOperateController.page回显。
问题描述
任意登录用户以恶意 UA 发请求 → 管理端日志页回显触发 XSS(依赖前端渲染方式)。
修复建议
- UA 入库前过滤;前端日志页禁用 v-html。
🟢 3.19 【Low】机构/岗位/字典只读接口无鉴权
位置
SysOrgController.java:32-46,94-100—list/listByPid/nameList无@PreAuthorize;SysPostController.java:44-50,91-99—list/nameList无鉴权;SysDictTypeController.all、SysParamsController.page、SysThirdLoginConfigController.page(暴露clientSecret,见SysThirdLoginConfigVO.java:32)、SysSmsLogController.page(手机号+参数)、SysMailLogController.page(邮件收件人+主题+正文SysMailLogVO.java:31-40)、SysDictDataController.page、SysLogOperateController.page等。
问题描述
系统模块大量只读接口未做 @PreAuthorize,仅依赖"登录即可"。多数为低敏感(组织架构/岗位),但 SysMailLogVO.content、SysParamsVO.paramValue(可能含密钥)、SysThirdLoginConfigVO.clientSecret、SysSmsLogVO.mobile/params 属于敏感数据。
修复建议
- 统一为敏感列表接口补鉴权;
clientSecret、日志正文、参数值做脱敏。
🟢 3.20 【Low】其它
| 位置 | 说明 |
|---|---|
maku-framework/src/main/resources/auth.yml |
/actuator/** 在免认证白名单中。当前 pom 未引入 actuator starter,暂无实际暴露;一旦引入即完全公开。建议从白名单移除。 |
ServerExceptionHandler.java:43-46 |
404 响应反射 resourcePath(URL 可控),以 text/plain 返回,需前端以 HTML 渲染才有 XSS 风险。 |
SysAttachmentController 附件 url 无协议/域名校验 |
可存 javascript: 或外部链接,管理端渲染时诱导。 |
四、攻击面全景(免认证 / 认证入口)
免认证入口(auth.yml 汇总)
/sys/auth/captcha、/sys/auth/login、/sys/auth/token、/sys/auth/send/code、
/sys/auth/mobile、/sys/auth/third、/sys/third/callback/**、/sys/third/render/**、
/upload/**、/、/actuator/**、/v3/api-docs/**、/swagger/**、/swagger-ui/**、/doc.html、
/sys/third/callback/**、/sys/third/render/**、/new/**、/maku-generator/**
/upload/**免认证 → 已上传的恶意 HTML/SVG 对全网开放;/sys/auth/send/code免认证 → 短信轰炸 + 触发华为短信 SSRF;/v3/api-docs/**、/swagger-ui/**、/doc.html免认证 → 接口文档公开(knife4j 默认 disabled,springdoc 注释可启用);/maku-generator/**免认证且被maku.xss.exclude-urls排除。
已登录即可访问的高危接口(缺 @PreAuthorize)
GET /sys/user/page → 全量用户枚举(数据权限被注释)
GET /sys/log/operate/page → 操作日志(密码哈希/密钥/参数)
GET /sys/log/login/page → 登录日志(用户名/IP)
GET /sys/mail/config/list → 邮件 SMTP 密码 + 云密钥
POST /sys/mail/config/send → 任意邮件中继
GET /sys/sms/config/list → 短信云密钥
GET /sys/mail/log/page → 邮件收件人+正文
GET /sys/sms/log/page → 短信手机号+参数
GET /sys/third/config/page → OAuth clientSecret
GET /sys/dict/type/all → 触发存储型 SQL 注入
POST /sys/file/upload 等 → 任意文件上传(穿越)
POST /ws/message/send → 向任意用户推送消息
五、修复优先级建议
- 立即(P0)
- 修上传路径穿越 + 加扩展名白名单 + 加
@PreAuthorize(阻断任意文件写/RCE 链); - 移除
dictSql动态执行或加关键字白名单(阻断存储型 SQLi); - 修
Query.orderORDER BY 注入(全局列名白名单); - 删除 SQL 脚本与配置中的真实密钥/默认口令;生产强制改密、启用 Redis/MQTT 认证。
- 修上传路径穿越 + 加扩展名白名单 + 加
- 尽快(P1)
- 给所有敏感
list/page/send补@PreAuthorize,VO 对密钥/日志正文脱敏; - 恢复用户/机构等数据权限过滤;
- SM2 密钥改为部署期生成;密码存储换带盐慢哈希;
- 收紧 Redis 反序列化类型白名单。
- 给所有敏感
- 规划(P2)
- 出站 URL 加内网/IP/协议白名单(SSRF);TLS 校验恢复;
- OAuth state 校验、
postMessage指定 origin、refreshToken 轮换; - Quartz 方法白名单;CORS 固定域名;移除 actuator/接口文档免认证白名单。
六、审计范围与方法
- 范围:
maku-framework、maku-boot-system、maku-boot-module(generator/iot/member/monitor/quartz/websocket)、maku-boot-new、maku-server,忽略target。 - 方式:静态源码审计。反序列化/RCE/命令执行/URLClassLoader/Groovy/SpEL/ScriptEngine/fastjson 等经全库检索未发现直接利用点;未做动态利用验证,以上均为静态推演结论。
- 依赖版本:Spring Boot 4.0.6、MyBatis-Plus 3.5.16、hutool 5.8.28、jsoup 1.16.1、fastexcel 1.2.0、JustAuth 1.16.6、Redisson 4.1.0、BC 1.69。
审计报告由自动化扫描 + 人工验证生成;严重度按 CVSS 倾向评估。