你的云数据库是 Security Theater
Source: Dev.to
传统多租户 SaaS 存储的问题
多租户 SaaS 存储在架构层面上根本存在安全隐患。供应商承诺行级安全、每个查询都带有租户 ID,以及静态加密,但一次 SQL 注入或特权提升漏洞就可能暴露 所有 租户的数据。一次泄露可能影响成千上万的受害者。
传统 SaaS 架构
┌─────────────────────────────────┐
│ Application Layer │
│ (trusted, handles isolation) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Database (ALL tenant data) │
│ WHERE tenant_id = ? │
└─────────────────────────────────┘
- 一个缺失的
WHERE子句、一个被攻破的 API 端点,或一个 IDOR 漏洞都可能危及每个租户。 - “静态加密”并不奏效,因为加密密钥与提供查询的系统位于同一处。它只能防止物理盗窃,无法阻止拥有数据库访问权限的攻击者。
Source: …
BSFS:存储层的密码学隔离
BSFS(块存储文件系统)消除了应用内部的共享数据库和信任边界。如果没有密钥,数据不存在。
核心概念
- 无共享数据库 – 每个租户使用其独立的加密分区。
- 密码学隔离 – 元数据和数据使用租户专属密钥加密;无需访问控制检查。
通过加密块分配表(BAT)的原子提交
- 分配随机块地址。
- 将新文件数据写入这些块。
- 更新加密的 BAT。
- 将旧块标记为空闲。
BAT 的更新即提交点。如果进程在写入过程中崩溃,读取者仍然看到旧文件;新块则成为垃圾。没有损坏、没有部分写入、也没有“最终一致性”的胡说。
// The atomic commit point
bsfs_encrypt_bat(partition_key, bat, encrypted_bat);
fseek(blob_file, partition_offset, SEEK_SET);
fwrite(encrypted_bat, sizeof(bsfs_bat_t), 1, blob_file);
fflush(blob_file);
// Transaction committed. Readers see new file.
- 在
fwrite之前崩溃 → 旧文件保持完整。 - 在
fwrite之后崩溃 → 新文件已提交。
密钥派生
每个租户获得一个主密钥。分区密钥通过 HKDF 派生:
Master Key → HKDF(partition_id) → Partition Key
- 主密钥可以派生任意分区密钥。
- 分区密钥不能派生兄弟密钥。
这提供了真正的密码学隔离,而不仅仅是访问控制检查。
随机块分配
BSFS 故意使用 Fisher‑Yates 洗牌随机化块的放置。文件在分区内被散布,防止攻击者通过块访问模式推断文件结构或文件之间的关系。
什么是 BSFS(以及不是)
不是替代品
- PostgreSQL 或任何关系型数据库
- 分布式文件系统
- 键‑值存储
- 为数百万小文件或范围查询优化的系统
预期使用场景
- 真正的租户隔离
- 原子文件更新
- 加密元数据
- 为 SaaS 应用存储提供可预测的性能
可以把它视为 加密对象存储(例如具有加密边界的 S3 桶),而不是带有 tenant_id 列的行。
API 示例
C 示例
uint8_t master_key[32];
bsfs_tenant_t tenant;
bsfs_tenant_init(&tenant, "storage.blob", master_key);
bsfs_write_file(&tenant, file_id, data, size);
bsfs_read_file(&tenant, file_id, &data, &size);
bsfs_delete_file(&tenant, file_id);
bsfs_tenant_cleanup(&tenant);
Python 示例
from bsfs import BSFS, generate_master_key
import uuid
master_key = generate_master_key()
with BSFS('storage.blob', master_key) as fs:
file_id = uuid.uuid4()
fs.write_file(file_id, b'confidential data')
data = fs.read_file(file_id)
fs.delete_file(file_id)
操作限制
- 每个分区最多 64 个文件
- 最大文件大小 512 MiB(2 MiB 块 × 256 块)
- 单分区实现(计划支持多分区)
- 不支持流式 I/O —— 整个文件加载到内存中
- 单线程
何时使用 BSFS
- 构建多租户 SaaS 产品
- 合规监管要求严格的数据隔离
- 过去遇到行级安全漏洞的经验
- 需要对文件、文档或二进制大对象(blob)进行可证明的加密边界
何时不使用 BSFS
- 需要关系查询或复杂连接
- 存储数百万条小记录
- 需要分布式共识或高可用复制
- 威胁模型 不 包括数据库泄露
成本比较
云数据库会对 IOPS、存储和计算进行收费。BSFS 运行在本地 NVMe 上,使用原始磁盘 I/O,并仅对元数据进行加密。您可以避免:
- 数据库连接开销
- 查询优化器运行时
- 复制延迟
- “无服务器”附加费用
- 每租户数据库实例
单个 2 TB NVMe 硬盘即可为数十个租户提供真正的密码学隔离,其成本甚至低于每月一个托管 RDS 实例的费用。
结论
大多数 SaaS 的安全性是通过访问控制列表——社会惯例来强制执行的。BSFS 使跨租户数据访问 在密码学上不可能,而不仅仅是未授权的。这在经历了数十年的妥协捷径后,回归了第一原理。
进一步资源
- 视频演练(实现、写时复制语义、加密元数据)
- 源代码仓库: