数据分级标签设计与存储
标签这东西,说白了就是给数据贴个“身份牌”。你想想看,权限系统要控制谁可以访问什么数据,总得有个依据吧?这个依据就是标签。我早年在做一个政务云项目时,就因为标签设计得太糙,后期权限模型改了三轮,差点没被运维同事骂死。
所以这一章,咱们就聊聊标签到底该怎么设计、怎么存、怎么管。内容分三块:标签结构、嵌入方式、生命周期管理。
标签结构设计:等级、类别、访问范围
我个人习惯把标签结构拆成三个维度:等级、类别、访问范围。这样设计的原因,说起来很简单——你既要知道数据有多敏感,也得知道它属于什么领域,还得知道谁能看。
标签三元组示例: {等级: L3, 类别: 财务, 范围: 内部}
这表示:数据敏感度较高(L3),属于财务类别,只允许内部员工访问。
等级(Classification Level)
等级是标签的核心,直接决定加密强度和访问门槛。我建议至少分四到五级,太少了粒度不够,太多了管理成本爆炸。
| 等级 | 名称 | 典型数据 | 推荐加密算法 |
|---|---|---|---|
| L0 | 公开 | 产品介绍、新闻稿 | 不加密或对称加密 |
| L1 | 内部 | 内部通知、组织架构 | SM4 / AES-128 |
| L2 | 敏感 | 财务报表、员工薪资 | SM4 / AES-256 |
| L3 | 机密 | 客户隐私、交易记录 | SM4 + 密钥分割 |
| L4 | 绝密 | 核心算法、密钥材料 | 专用硬件加密 |
我曾经踩过这个坑: 把等级直接映射到加密算法强度,结果 L0 和 L1 用了同一种加密,审计时被质疑控制不足。后来我强制要求 L0 不加密,L1 以上才加密,逻辑就清晰多了。
类别(Category)
类别解决的是“数据属于哪个域”。比如财务、人事、研发、销售。同一等级下,不同类别的人可能权限不同。我建议类别用预定义枚举,别让业务方自己随便填,否则分分钟冒出几十个奇怪的类别名。
举个例子。一个财务部的L2数据,人事部的人就不能碰,哪怕他的等级够高。这就是类别在起作用。
访问范围(Scope)
范围定义了数据的“可见边界”。常见取值有:
- 个人 —— 仅数据所有者可访问
- 部门 —— 所属部门全员可访问
- 项目组 —— 项目成员可访问
- —— 全员可访问(通常仅限L0/L1)
这三个维度组合起来,就能描述绝大多数场景。我个人习惯在代码里用一个结构体来定义:
struct DataLabel {
uint8_t level; // 0-4
uint16_t category; // 枚举值
uint8_t scope; // 0-3
uint64_t timestamp; // 标签生成时间
};
标签嵌入方式:元数据、数据库字段、文件头
标签设计好了,接下来得考虑怎么跟数据绑在一起。嗯,这里要注意:不同的存储形态,嵌入方式完全不一样。我在项目中主要用过三种方式。
方式一:元数据(Metadata)
适用于对象存储、云存储、HDFS这类系统。标签放在文件的扩展属性或标签字段里,不修改数据本身。
# 给对象存储的文件打标签
PUT /bucket/user_data.csv
X-Amz-Tagging: level=3&category=finance&scope=internal
优点: 对数据零侵入,修改标签不用动文件。
缺点: 如果存储系统不支持元数据,就没法用了。
方式二:数据库字段(Database Column)
适用于关系型数据库。在每张表里加一个data_label字段,或者单独建一张标签关联表。
-- 方案A:直接加字段
ALTER TABLE user_info ADD COLUMN data_label VARCHAR(64);
-- 方案B:关联表(推荐用于多标签场景)
CREATE TABLE data_label_map (
table_name VARCHAR(64),
row_id BIGINT,
label_json VARCHAR(256)
);
我个人比较推荐方案B,因为标签可能跟随业务变化。方案A改起来太费劲,我之前一个项目就是用的方案A,后来加了个类别维度,跑了48小时做数据迁移,差点被运维点名批评。
小技巧: 标签字段建议使用 JSON 或 Protobuf 序列化存储,便于扩展。但注意,JSON 查询性能稍微差一点,高频访问场景建议用 INT 位掩码做等级和类别。
方式三:文件头(File Header)
适用于二进制文件、加密文件、压缩包。标签嵌入在文件头部的自定义字段里,通常配合加密一起用。
+----------------+----------------+----------------+
| 文件魔数(4B) | 文件版本(1B) | 加密标识(1B) |
+----------------+----------------+----------------+
| 等级(1B) | 类别(2B) | 范围(1B) |
+----------------+----------------+----------------+
| 保留字段(8B) | 数据内容... | |
+----------------+----------------+----------------+
这种方式的好处是标签和文件绑死,拷贝、传输都不会丢。坏处是改标签得重写整个文件。
标签生命周期管理
标签不是贴上去就完事了。数据会变老,敏感度会下降,访问范围也会调整。没有生命周期管理,标签就会变成一堆垃圾数据。
我总结了一个简单的三阶段模型:
- 创建期 —— 数据生成时首次打标签。通常由数据生产者或自动分类引擎完成。
- 维护期 —— 数据生命周期内,标签可能被复审、升级或降级。我建议设置一个标签复审周期,比如L3数据每半年复审一次,L2每一年。
- 废弃期 —— 数据删除或归档时,标签必须同步清理。否则审计时会有“幽灵标签”,看着吓人。
标签变更流程(简化版):
- 数据负责人发起标签变更申请
- 安全审计组审批(自动/人工)
- 更新标签存储(元数据/字段/文件头)
- 如果是降级,可能需要先解密再用新密钥重新加密
- 记录变更日志,保留旧标签快照(至少180天)
标签快照这事很有意思。有一次审计查半年前的数据,非要看当时的标签是什么。还好我们做了标签历史表,否则就得靠记忆了。
-- 标签历史表结构示例
CREATE TABLE label_history (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
data_id VARCHAR(128), -- 数据ID
old_label VARCHAR(256), -- 旧标签JSON
new_label VARCHAR(256), -- 新标签JSON
operator VARCHAR(64), -- 操作人
change_time DATETIME, -- 变更时间
reason VARCHAR(512) -- 变更原因
);
最后说一点。标签的生命周期必须和数据的生命周期对齐。数据销毁了但标签还在,那就是安全隐患。我在一个系统里见过100万条记录的数据表只剩10万条数据,但标签关联表里还有80万条记录——这就是典型的“标签泄漏”。
个人经验分享: 标签的生命周期千万别跟数据的生命周期完全解耦。我在一个项目中吃过亏——数据删除了,但标签还在,结果安全扫描时被当作“未授权数据残留”报告,白挨了一顿批评。后来我强制要求标签表和数据表用同一个主键,删除时级联删除标签,问题才彻底解决。