第 2 章 字段级加密SDK常见架构与设计模式归纳总结

做这一行久了,你会发现字段级加密SDK的架构来来去去就那么几套。我刚开始接触时也觉得设计很玄乎,后来拆过好几个商业SDK的源码,嗯,其实核心骨架都差不多。这一章咱们就把它们扒开看看。

2.1 整体架构分层

说白了,一个能扛住生产环境的字段级加密SDK,通常分四层。每层各司其职,改一层不影响别的层——这一点在版本升级时特别重要,我吃过亏。

  • 接口层(API Layer):对外暴露encrypt、decrypt、mask等统一方法。只关心入参出参,不关心底下怎么算。
  • 加密策略层(Strategy Layer):根据字段元数据(如算法、密钥ID)选择具体加密方案。这里是设计模式的重灾区(后面细讲)。
  • 密钥管理层(Key Management Layer):拉取、缓存、轮换密钥。记得当年线上事故就是因为密钥拉取超时没降级……
  • 底层加密库(Crypto Provider):调用原生或第三方加密实现(OpenSSL、Bouncy Castle、国密SM4等)。

关键点:层与层之间通过抽象的接口交互,不要直接引用具体实现类。否则SDK版本升级时你会被“循环依赖”搞得想骂人。

2.2 核心设计模式

这里列几个我个人工程里必用的模式,不扯理论,直接说拿来干嘛。

模式 解决什么问题 我的踩坑案例
策略模式 字段A用AES-256,字段B用国密SM4,运行时根据注解/配置切换算法 曾经把所有if-else写死在service里,升级加一种算法改了十几个文件
装饰器模式 给加密结果加版本号、做缓存、做日志,不污染核心加密逻辑 用继承实现缓存,结果子类爆炸,换装饰器后清爽多了
工厂模式 根据版本号自动创建兼容旧版解密器,方便向后兼容 有个项目手写Map硬编码版本映射,新版本加了漏掉旧版,线上解密失败
模板方法 加密/解密流程固定(校验参数→获取密钥→执行算法→处理结果),子类只重写算法部分 以前每加一个加密算法都复制整个流程,改了流程就要改N处

一个小建议:设计初期就把这些模式嵌进去,别等SDK发布V2.0再重构。我在V1.0时偷懒没用策略模式,V2.0改了一个半月,还被客户投诉API不兼容。

2.3 架构选型对比

不同的业务场景,适合的架构也不太一样。我整理了一个对比表,你可以拿来当参考。

架构风格 优点 缺点 典型场景
单体胖SDK 部署简单,依赖自包含 升级困难,二进制体积大 嵌入式设备、Android客户端
微服务+瘦SDK 加密逻辑集中管理,客户端只做网络调用 增加网络延迟和依赖 高并发后端服务、多语言环境
插件式+SPI 算法/密钥源可热插拔,兼容性极好 接口设计复杂,调试困难 多云密钥管理、合规审计

特别注意:单体胖SDK里千万别把Key和密文写死在一起。我曾经接手过一个项目,加密SDK自带了一个硬编码的默认密钥——测试环境用的,结果客户直接上了生产。嗯,后果你懂的。

2.4 一张图看懂架构

下面这张图表是我自己项目里截出来的简化版。你可以把它当作设计SDK时的“脚手架”。

字段级加密SDK典型架构分层 应用层(客户端/服务端) SDK接口层(encrypt/decrypt/mask) 加密策略层(算法路由、元数据解析) 密钥管理层(KMS/本地缓存/轮换) 底层加密库(AES/SM4/OpenSSL) 向上依赖接口 层级解耦

注意看,每一层都只和下一层通过抽象接口通信。我习惯在接口层放一个版本号协商逻辑——客户端传个版本号,策略层自动选择对应的解密流程。这样升级时就不用停服了。

2.5 避坑指南

最后说几个我用真金白银换来的教训。

  • 别把密钥信息硬编码在SDK里:哪怕测试环境也不行。我曾经觉得“临时用一下”,结果被合规部门查出来,补了三个月的整改报告。
  • 版本兼容不是“加个if”那么简单:旧版密文格式可能没有版本号字段,解密时怎么识别?我建议第一期设计就在密文头部留2个字节做魔数+版本。
  • 加密策略层要支持动态加载:否则每次加新算法都得发版。用SPI或者类似机制,让用户自己实现接口,放到classpath就行。

我的小工具:写了一个代码生成器,根据你定义的字段元数据自动生成策略层代码。虽然不算完美,但至少避免了手写重复的Factory类。感兴趣的话可以拿去改改。