34-安全复盘96个问题

34-安全复盘:96个评审问题与修复

522行CODE_REVIEW_REPORT记录了96个问题------16个CRITICAL、26个HIGH、26个MEDIUM、28个LOW。最危险的是2.11组合攻击链:无鉴权+SQL拼接+rawSql=全库泄露。这篇复盘CRITICAL级的11个问题、P0-P3优先级体系、以及修复后的验证闭环。

文章目录

素材:D:\work\browise\CODE_REVIEW_REPORT.md(522行)+ BROWISE-STATUS.md修复记录


一、评审的全景

维度 数据
范围 13个Maven模块+Vue前端
Java源文件 214个
Vue/TS源文件 91个
总问题 96个
CRITICAL 16个
HIGH 26个

96个问题不是写得烂------是认真查了 。667个单测100%通过的系统照样有16个CRITICAL------测试通过≠安全。单测验证"功能对不对",评审发现"能不能被恶意用"。


二、最危险攻击链:2.11的三段组合

复制代码
第一段: EaAdminController无鉴权        (formbuilder)
   ↓ 任意登录用户可POST /ea/admin/save
第二段: SqlBuilder固定值直接拼接       (metadata)
   ↓ 恶意SQL片段写入EA05条件元数据
第三段: /ea/query执行rawSql           (formbuilder)
   ↓ 拼接的SQL随查询执行

结果:数据库全量泄露与篡改。

单独看每一段都不致命------admin接口没鉴权("内部系统先跑起来")、固定值拼接("值来自配置表是可信的")、rawSql执行("#{param}是参数化的")。三段串起来是完整绕过。这就是评审必须跨模块看的原因------单模块review看不到组合面。

修复三件套(已全部落地):

java 复制代码
// ①EaAdminController每个方法加checkAuth
private void checkAuth() {
    UserProfile p = CurrentUser.get();
    if (p == null || !adminList.contains(p.getPsnId()))
        throw new BrowiseException(403, "无元数据管理权限");
}

// ②改删接口的固定值也走占位符(第07篇appendWhereConditions)
sql.append(c.getColumnName()).append("=?");    // 原来是='值'直接拼
paramValues.add(c.getConditionValue());

// ③rawSql强制#{}参数化(第11篇)------占位符替换从根上堵注入

三、其他CRITICAL的修复对照

2.1 JWT Secret硬编码(第25篇已讲修复)

java 复制代码
// 修复前
private String secret = "browise-platform-jwt-secret-key-2026";  // 源码里的死密钥

// 修复后:@PostConstruct启动校验------无配置或短于32字符直接起不来

2.3/2.4 RowSet的两个脏标记CRITICAL(第19篇专述)

  • reject()用clear()清数据而不是_o恢复 → 修复为clear+putAll(originals)整体替换
  • accept()不清originals → 修复为复位全部状态承载

有意思的对照 ------评审报告指出"TypedRowSet.reject()实现正确"------同一个协议的两个载体,一个对一个错。没有共享实现的协议=语义漂移的温床。修复后两边行为对齐,但代码依然是两份(泛型/Map载体差异所致)------评审建议的"抽公共trait"在Java 8里没有优雅解法,靠测试锁定行为等价(BaseEntityTest 24个用例)。

2.5 事务竞态(第06篇已讲修复)

java 复制代码
// 修复前:catch里rollback + finally里无条件commit------异常后先滚再提交!
} catch (EaException e) {
    if (myTrans) provider.rollback();
    throw e;
} finally {
    if (myTrans) provider.commit();     // ← rollback之后又commit了空事务
}

// 修复后:success-flag------只有成功路径才commit
boolean success = false;
try { ...; success = true; return; }
finally {
    if (myTrans) { if (success) commit(); else rollback(); }
}

2.7 KingBasePg参数顺序(第09篇已讲)

LIMIT ? OFFSET ?的参数序是size,offset------引擎按ROWNUM习惯追加min,max------supportsOffset()布尔值就是这次修复的产物。

2.9 前端XSS:innerHTML+script注入

ApproveForm把审批表单HTML直接innerHTML渲染、script用createElement执行------恶意流程表单=存储型XSS=偷所有查看者的JWT。修复引入DOMPurify过滤。

2.10 路径遍历(第04篇提过)

java 复制代码
// 修复前
new File(uploadPath, fileName);   // fileName="../../../etc/passwd"直接拼

// 修复后:normalize+startsWith白名单
Path resolved = Paths.get(uploadPath).resolve(fileName).normalize();
if (!resolved.startsWith(Paths.get(uploadPath))) throw new SecurityException();

四、P0-P3优先级:修复的排序法

复制代码
P0(立即修)--- 11个:全部CRITICAL安全+数据损坏
   JWT硬编码/密码明文/SQL注入/XSS/路径遍历/RowSet损坏/事务竞态...
P1(本迭代)--- HIGH里的正确性问题
   连接泄漏/分页参数/BaseEntity脏标记误报/前端绑定失效
P2(下迭代)--- MEDIUM性能与健壮性
   反射缓存/空catch/日志脱敏
P3(择机)  --- LOW规范类
   命名/Javadoc/魔法数字

P0的11个已全部修复 (BROWISE-STATUS的P0-2.x系列)------修复记录每条带问题编号对应回评审报告,形成"发现→定级→修复→记录"的完整闭环。


五、这次评审的方法论价值

三层视角缺一不可:

视角 能发现 单测能不能发现
功能正确性 reject恢复错值 能(但没写这个用例)
安全攻击面 无鉴权+注入组合 不能------单测不模拟攻击者
跨模块组合 三段攻击链 不能------单测按模块隔离

"667个测试全通过"和"16个CRITICAL"同时成立 ------这个事实本身就是最深的教训:测试覆盖的是你想到的路径,攻击者走的是你没想到的路径。


六、遗留的LOW们要不要修

28个LOW(空catch、命名、注释)------择机修 。不是不重要,是机会成本:修28个LOW的时间够写3个新功能。只要LOW不升级(空catch在关键路径出现就该提级),技术债的利息可控。

评审报告的价值不是"96个都要修"------是让每个问题有编号、有定级、有去向(修了/择机/不修的理由)。看不见的债才可怕。


✅ 亮点:2.11三段组合攻击链的完整剖析(单段无害组合致命)、修复与前期篇章的交叉引用闭环、success-flag修复对照、P0-P3的排序逻辑、"667测试通过与16个CRITICAL并存"的方法论教训。适合建立代码评审体系的人。扩展方向:第57篇667单测、第58篇18个bug修复史、第31篇TrustAll教训。

相关推荐
卸任3 小时前
Vibe coding工具使用心得
前端·ai编程
brien94 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance4 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M4 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写4 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李4 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
Flynt4 小时前
日涨4000星的OSINT工具,我拿Linus的用户名和一个随机字符串实测了一遍
python·安全
陈随易4 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马4 小时前
前沿视界
前端
kyriewen4 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员