报表工具通常以 JAR 包的形式集成进业务系统,升级时最怕的是“升完之后某个功能突然不能用了”。积木报表(JimuReport)v2.5.5 就有一处需要提前处理的变更:报表保存接口补上了鉴权,升级后如果没给角色配权限,设计器会保存失败。
这篇文章围绕 v2.5.5 的几处安全修复和 Word 导出问题,讲清楚每个问题的成因、修复方式,以及集成方升级前需要做什么。
一、保存接口缺少鉴权:为什么能“往任意表写数据”
问题编号 GHSA-6jgq-56jw-r3p6(issues/4817):/jmreport/save 缺少鉴权,任意登录用户都可以自建填报报表,并借助填报功能往任意表写数据。
填报报表的本质是“一张绑定了目标表的表单”。保存接口如果只校验“已登录”,普通用户就可以提交一份报表配置,把填报目标表指向系统里的用户表、权限表,再通过填报页写入数据。这类问题的根源是设计器接口和使用者接口没有区分权限。
v2.5.5 的修复是:保存、复制、导入报表配置改为需要显式授权,并要求当前用户具备 admin 或 lowdeveloper 角色之一。
| 权限标识 | 对应接口 |
|---|---|
jmreport:design:save |
/jmreport/save、/reportCopy、/importReportConfig |
集成方要做的事:升级前给负责设计报表的角色分配 jmreport:design:save。在 JeecgBoot 这类基于 Shiro/Spring Security 的系统里,就是在菜单管理中新增一个按钮权限,再到角色授权里勾选。
二、生产模式下的配置越权读取
issues/4811:生产模式(lowCodeMode=prod)原本就会拦截设计器相关接口,但 get/{id}、field/tree、loadDbData 三个接口漏在拦截范围外,可以读到报表配置和数据源表结构。SaaS 模式下,设计器配置接口也没有做租户归属隔离。
这类问题很典型:拦截规则按“接口清单”维护,新增接口时容易漏掉。比较稳妥的做法是反过来,设计器接口统一放在一个路径前缀下,生产模式按前缀整体拦截,再对预览需要的少数接口单独放行。
以集成在 JeecgBoot 中为例,生产模式在 application.yml 中这样开启:
jeecg:
firewall:
# 低代码模式(dev:开发模式,prod:发布生产环境 — 关闭所有在线开发配置能力)
lowCodeMode: prod
三、分享 JWT:固定密钥的问题
GHSA-fr4f-cch7-3f24:分享链接用 JWT 做签名,但签名密钥是写死在代码里的。开源项目的固定密钥等同于公开,任何人都可以自己签出一个合法的分享 token。
v2.5.5 的改法是按每条分享记录单独派生密钥,并统一验签逻辑。思路可以概括为:
// 每条分享记录派生独立密钥:泄露一条不影响其他分享,删除分享记录即令 token 失效
byte[] key = hmacSha256(serverSecret, "share:" + share.getId() + ":" + share.getCreateTime());
String token = Jwts.builder().subject(share.getReportId())
.expiration(share.getExpireTime())
.signWith(Keys.hmacShaKeyFor(key)).compact();
另外两处细节也值得注意:
- 分享页 Cookie 验签失败后不再自动续签。否则伪造的 Cookie 会被“续”成合法的;
- 钻取跳转用的 Cookie 也补上了验签,钻取页面不能绕过分享校验。
四、fastjson autoType
v2.5.5 把 fastjson 升级到 2.0.66,修复 autoType 哈希碰撞可加载任意类的漏洞(GHSA-59gp-673v-hxh2)。如果你的宿主项目自己也依赖 fastjson,要注意 Maven 的依赖仲裁:宿主声明的版本会覆盖报表 JAR 带进来的版本。可以用下面的命令确认最终版本:
mvn dependency:tree -Dincludes=com.alibaba.fastjson2
五、Word 导出的几个排版问题
安全之外,v2.5.5 集中修了一批 Word 导出问题。它们的共同原因是:报表的单元格模型是“网格 + 合并”,而 Word 的表格是“流式布局 + 自动分页”,导出时需要估算每行在 Word 里的实际高度。估算不准,就会出现以下现象:
- 某一行超过一页高时,后面的合并单元格错乱、被拆到两页,下一页标题格为空:跨页时合并区域需要在新页上重新补齐标题;
- 纵向合并跨页后,同页其他单元格的合并丢失:跨页拆分只应作用于被拆开的那个合并区域;
- 含数字、英文的单元格显示不全:行数估算原来按字符数平均计算,现在按 Word 的断行规则估算(英文按单词断行);
- Office 中多出空白页:页码段落的段前段后间距导致最后一页溢出,现在清零并使用单倍行距;
- 自适应高度的行显示不全:行高按单倍行距重新估算。
如果你之前为这些问题在模板里加过空行、手动调过行高,升级后建议重新导出核对一遍。
六、填报的两处增强
- 数据字典可以用系统已有的字典(issues/4797):集成方实现
JmReportTokenServiceI#getDictList接口即可,不必在积木报表里再维护一份;表字典还支持加 SQL 过滤条件; - 预览布局:新增“预览居中”和“预览铺满”两种显示方式(issues/4706)。
七、示例工程的默认口令
使用 jimureport-example 独立部署的用户注意:v2.5.5 去掉了默认口令 admin/123456。未配置口令或口令仍为 123456 时,每次启动会随机生成口令并打印到启动日志。可以用环境变量固定:
export JIMU_ADMIN_PASSWORD='your-strong-password'
或在配置文件中设置 spring.security.user.password。
升级检查清单
- 给设计报表的角色分配
jmreport:design:save,并确认这些用户具备admin或lowdeveloper角色; - 生产环境确认
lowCodeMode: prod; - 用
mvn dependency:tree确认 fastjson 最终版本不低于 2.0.66; - 已发出的分享链接在升级后会按新规则验签,必要时重新生成;
- 独立部署的示例工程,到启动日志里查看随机口令或配置
JIMU_ADMIN_PASSWORD。
依赖坐标(Spring Boot 3):
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot3-starter</artifactId>
<version>2.5.5</version>
</dependency>
Spring Boot 4 使用 jimureport-spring-boot4-starter,版本相同。