不彻底重写,如何修复金融科技系统架构
金融科技架构修复,是在不替换整套系统的前提下,有控制地修复一个线上金融产品的安全、数据和交付边界。更稳妥的顺序是:建立可追踪的发现,稳定语言与持久化基础,显式化依赖,关闭授权和资金完整性缺口,再通过预发布环境与发布门禁证明结果。
本文只回答修复问题:架构或安全审查在一个涉及资金流的产品中发现问题后,下一步该怎么做?前置诊断请参考vibe-coded 软件审计指南。如果同时涉及供应商更换,请使用软件项目接管的 30 天计划。
起始架构是什么样的?
产品包含 Node.js 与 Express 后端、PostgreSQL、Redis、浏览器与移动端客户端、带服务端 API 路由的 Next.js 界面、多套身份与支付集成,以及基于 EVM 的交易路径。部分代码由异构、部分 AI 生成的实现模式快速扩展而来。问题并非某个模块写得不好,而是系统里同时存在多种服务构造、数据查询、用户识别和外部事件处理方式。
| 边界 | 初始模式 | 风险 |
|---|---|---|
| 应用契约 | 无类型 JavaScript、宽泛对象和局部接口 | 错误假设要到运行时才暴露。 |
| 服务归属 | 静态方法、全局实例、直接构造和服务定位器 | 难以追踪或替换真正在线的依赖路径。 |
| 持久化 | 原始 SQL、旧模型门面和多种数据访问模式 | 事务、模式规则和查询归属容易分叉。 |
| 身份 | 信任调用方提交的用户与对象 ID | 通过身份认证不等于有权访问目标对象。 |
| 资金流 | 幂等、锁和 Webhook 处理不一致 | 重试或部分失败可能让资金效果发生两次,或一次也没发生。 |
| 发布证据 | 大型变更集与持续变化的预发布环境 | 一个发现看似修复,另一条路由却仍走旧实现。 |
一次性的扫描报告无法治理这套系统。Wavect 在多轮审查中持续维护稳定的发现 ID、严重度、源码位置、风险、修复方向和复测条件。这与 NIST 安全软件开发框架的思路一致:代码审查、问题分诊和修复建议应进入开发工作流,而不是只在发布前执行一次。
六层架构修复顺序
顺序本身就是最重要的架构决策。如果构造、持久化和身份仍然含糊,就先修业务缺陷,只会产生更多并行实现。因此每一层都必须有明确的退出证据。
| 顺序 | 修复层 | 退出证据 |
|---|---|---|
| 1 | 可追踪风险基线 | 稳定发现 ID、在线路由图和明确关闭条件 |
| 2 | 类型化应用基础 | 严格 TypeScript、共享请求上下文、DTO 和类型化错误 |
| 3 | 依赖与持久化边界 | 单一组合根、构造函数注入、仓储层数据访问和显式启动 |
| 4 | 授权与数据最小化 | 服务端身份、对象所有权检查和回归测试 |
| 5 | 资金与供应商完整性 | 持久化幂等、已验证 Webhook、对账标记和失败关闭 |
| 6 | 预发布与上线准备 | 关键流程复测、恢复证据和书面上线决策 |
1. 把报告变成持续运作的修复系统
每个问题从发现、实现到复测都保留同一个 ID。关闭说明必须指向真实行为变化,不能只指向拉取请求标题。后续审查明确区分四种状态:已修复、部分修复、仍存在、缺少实现。这样,新增一个 guard 并不会自动算作完成,因为生产路由可能仍在调用旧控制器。
实际审查单位是路由或用户旅程,而不是单个文件。审查者从认证一路追踪到控制器、服务、仓储和外部效果。系统存在多套实现时,第一步是确认哪一套真正承接流量。
2. 在大范围业务重构前建立类型基础
后端迁移到严格 TypeScript,并统一实体、请求上下文、响应封装、领域契约和应用错误。类型从业务逻辑文件中移出,进入责任明确的模块。深层相对导入替换为领域别名。
类型本身不会让系统自动安全。它的价值是让假设可见、可审查。用户 ID、供应商事件和交易状态不能再在不同服务中拥有不同形状而不被编译器发现。
3. 让构造与持久化变得简单、单一
服务构造集中到一个 HTTP 组合根。领域代码通过构造函数接收依赖。导出的服务实例、静态业务方法和领域层内部的容器查找被移除。控制器不再接收全局 DataSource,只接收所需的具体服务或仓储。
持久化统一到 TypeORM 实体和领域仓储之后。只有复杂查询确有必要时才保留受控原始 SQL。数据库初始化成为明确的启动职责,运行时建表退出线上资金路径,自动模式同步保持关闭。TypeORM 迁移文档明确指出,当生产数据库已有真实数据时,自动同步通常并不安全,迁移才是受控更新模式的方式。
4. 在服务端确定身份,并授权每个对象
身份认证只回答请求是谁发出的,不能回答这个人能否读取某个群组、修改某笔交易或查看其他用户记录。修复过程把操作划分为本人、成员、管理员和供应商签名范围,并采用默认拒绝。
客户端提交的用户 ID、手机号、钱包 ID 和交易 ID 只作为查询输入,不再作为权限证据。认证上下文提供身份。共享 guard 统一检查本人、成员关系、角色和所有权。响应经过过滤,只向客户端返回当前旅程需要的身份与金融字段。
OWASP API1:2023 对象级授权失效描述的正是这类问题:每个接收对象标识符的端点,都必须检查当前用户是否有权对该对象执行请求操作。随机 ID 可以降低猜测概率,却不能替代授权。
5. 按照重试、重复和部分完成来设计支付路径
资金 API 往往在最麻烦的位置失败。系统可能已经更新余额,却丢失响应,随后供应商再次发送事件。两个事件可能表达同一个业务结果。较晚状态也可能先到。外部回调可以是真实的,但随后的数据库操作仍可能失败。
修复加入了按用户隔离的幂等记录、请求体哈希、持久化响应,以及在持久幂等不可用时明确阻止生产处理。独立的余额应用标记区分“事件状态已记录”和“资金效果已完成”,因此重复状态不会跳过尚未完成的余额工作。
Webhook 验签移动到监控记录和状态变更之前。不可信的运维回调在确定可信调用方和密钥前保持关闭。Stripe Webhook 文档很好地说明了供应商无关的原则:验证签名,预期重试和重复,不依赖事件顺序,并把复杂处理移出确认响应路径。
6. 在预发布环境证明产品,而不只做静态检查
最后一轮覆盖群组生命周期、存取款、钱包交接、供应商失败、响应式布局和后端信任边界,并记录可复现 ID、截图、已验证行为和剩余风险。静态审查只能证明签名检查存在。代表性流程才能证明正确路由真的调用它,以及用户能否从失败中恢复。
受审查快照发生了什么变化?
| 测量项 | 结果 | 证明内容 |
|---|---|---|
| TypeScript 范围 | 应用、脚本和测试共 275 个文件 | 应用不再同时维护 JavaScript 与 TypeScript 两套实现。 |
| 可注入类 | 125 | 服务依赖拥有显式构造点。 |
| 构造函数注入点 | 317 | 依赖可以被审查和替换。 |
| 容器解析 | 只存在于路由与启动组合 | 领域代码不再通过服务定位器隐藏依赖。 |
| 数据库访问 | 控制器与服务不再使用应用 DataSource | 持久化责任位于仓储边界之后。 |
| 静态异步业务方法 | 服务与控制器目录中为零 | 业务行为使用实例依赖,而不是全局状态。 |
这些是结构测量,并不表示所有风险都已消失。自动化覆盖仍需增加,外部供应商仍会失败,智能合约审查仍是独立发布门禁,大型领域服务也仍需选择性拆分。
为什么小型拉取请求比整洁架构图更重要?
早期修复候选一次打包了数十个发现。其中一个在约 85,000 行变更中处理 27 个追踪项,另一个仍包含约 50 个发现。AI 辅助实现生成代码的速度,超过了人工验证组合行为的速度。
交付方式随后改为每个拉取请求只处理两到三个相关发现,并尽量控制在约 20 个文件。基础分支按依赖顺序堆叠。每个分支都需要实现计划、测试证据、人工审查,以及合并后的源码复核。最终合并分支还要再审查,因为单独正确的分支组合后仍可能形成错误系统。
这是增量现代化,不是保留所有旧决策的借口。Martin Fowler 对 Strangler Fig 模式的说明解释了逐步替换的价值:现有系统继续服务用户,同时让投资与结果逐步可见。本案的切缝是类型、组合、仓储、授权和供应商适配器,而不是一次性替换平台。
金融科技产品什么时候可以发布?
- 发现关闭:每个阻断项都有源码变更、复测和剩余风险负责人。
- 关键旅程:认证、生命周期、存款、取款与故障恢复在代表性环境中通过。
- 资金完整性:重复、延迟、无效和部分完成事件都有确定结果与对账路径。
- 运营恢复:部署、回滚、监控、事故责任和数据恢复都有可用证据。
- 外部保证:应用代码之外的供应商和智能合约风险拥有独立测试或审查。
不要把这份清单变成监管合规声明。义务取决于产品角色、市场、数据和支付模式。架构修复为合格的安全、法律和监管评估提供工程证据,但不能替代这些评估。
应该原地修复、选择性替换,还是重建?
| 决策 | 适用条件 | 第一个商业步骤 |
|---|---|---|
| 原地修复 | 业务旅程有价值,边界可以被显式化 | 购买范围明确的架构与发布准备评估。 |
| 选择性替换 | 身份、支付或持久化的某个边界集中制造风险 | 为该边界定义共存、迁移和回滚条件。 |
| 完整重建 | 核心数据模型无法表达产品,或安全共存成本高于替换 | 要求基于证据比较整体迁移风险。 |
Wavect 的软件质量保障服务可以把金融代码库转化为可追踪的风险与修复计划。IKB 敏感系统集成案例提供另一份相关交付证据,从 vibe-coded 原型到生产的指南则帮助判断更大的加固范围。如果资金、身份或供应商回调已经穿过系统,请申请独立金融科技架构审查。
需要一套团队可以执行、又不必停掉产品的修复顺序?
评估金融科技架构审查金融科技架构修复常见问题
什么是金融科技架构修复?
vibe-coded 金融科技产品能达到生产标准吗?
金融科技后端应该从零重写吗?
金融科技架构评估应交付什么?
为什么幂等对支付系统至关重要?
如何验证架构修复真的生效?
最终思考
真正可用的重写替代方案,不是无限打补丁,而是一套有顺序的修复计划。从发现、源码变更、回归测试,到预发布行为和发布决策,必须保留一条完整证据链。
先稳定语言与持久化基础,再显式化依赖与身份。把支付重试和供应商回调当作正常运行条件。让拉取请求小到足以真正验证。这样,既有产品可以在继续服务业务的同时,变得更安全、更容易负责。
