SSE-C 基本概念与工作原理
SSE-C,全称 Server-Side Encryption with Customer-Provided Encryption Keys。说白了,就是你把加密密钥交给 S3,S3 用这把密钥帮你加密数据,但 S3 不保存 你的密钥。密钥用完即弃?嗯,准确说,每次请求你都得带上密钥,S3 只临时用一下,加密完就扔掉。我在项目中遇到过不少团队对这一点理解有偏差,以为 S3 会记住密钥,结果下次下载时没带密钥,死活拿不到数据……
一句话总结:SSE-C 让你 自己管钥,S3 只负责 临时借用 加密/解密,用完就忘。
核心要素
要搞懂 SSE-C,先抓住四个关键点:
- 客户提供的密钥:一个 256 位的 AES 对称密钥,由你在客户端生成。
- 密钥的 MD5 哈希:将密钥做一次 MD5,作为校验令牌发给 S3。S3 不会存你的原钥,只存这个哈希,用于后续验证。
- 加密算法:固定用
AES-256-CBC,没得选。 - S3 不存储密钥:我特意强调一下——密钥只在请求生命周期内存在,请求结束立刻丢弃。你想想看,如果 S3 真的把密钥持久化了,那还叫什么“客户提供”?
工作流程
我们以一次 上传 和一次 下载 为例,把整个过程走一遍。这里我习惯用 三步走 来记:
- 生成密钥:你在客户端生成一个 256 位 AES 密钥,自己保管好。
- 上传对象:在 PUT 请求的 HTTP Header 里带上三个参数:
S3 收到后,用你提供的密钥加密对象,将密文存入磁盘,并把密钥的 MD5 哈希记录在对象的元数据中。x-amz-server-side-encryption-customer-algorithm: AES256 x-amz-server-side-encryption-customer-key: Base64(你的密钥) x-amz-server-side-encryption-customer-key-MD5: Base64(MD5(你的密钥)) - 下载对象:你再次发送 GET 请求,同样带上那三个 Header。S3 先校验你给的密钥的 MD5 是否与存储的哈希一致——通过了就用它解密,返回明文;不通过直接返回
403 Forbidden。
我曾经遇到过一个大坑:客户端 SDK 默认会对密钥进行 Base64 编码,但有人手动拼接请求时忘了这一步,直接把二进制密钥塞进 Header……结果 S3 报错说“非法密钥格式”。嗯,整整排查了半天。所以 务必确认你的密钥是经过正确 Base64 编码的字符串。
小技巧:用 AWS CLI 或 SDK 时,
--sse-customer-key 参数会自动帮你做 Base64 编码,省心很多。但如果你用 curl 手动调试,一定要自己转一下。
注意事项与避坑
- 密钥丢失 = 数据丢失:S3 不帮你保存密钥,你丢了密钥,就等于丢了加密后的对象。我见过有人把密钥存到笔记本的便签里,结果笔记本丢了……
- 每次请求都得带密钥:不适合高频访问的场景,因为每次都要传递 32 字节的密钥,网络开销和延迟都变大了。
- 必须使用 HTTPS:密钥在 HTTP Header 中明文传输(Base64 只是编码,不是加密),如果走 HTTP,相当于把密钥裸奔。我个人建议 永远不要用 HTTP 访问 SSE-C 的对象。
- 已加密对象无法更新元数据:如果你想修改对象的元数据(比如 Content-Type),必须先下载解密,再重新上传加密。因为元数据本身也是加密存储的。
一张图看懂 SSE-C 的工作流程
下面这张流程图把上传和下载两条路径画到一起了。你从上往下看,客户端左边是上传,右边是下载。
再次强调:SSE-C 不提供密钥托管能力。如果你需要 S3 帮你管理密钥,请用 SSE-S3(使用 AWS 托管的密钥)。但如果你有合规要求,必须自己掌控密钥,SSE-C 就是你的菜。
SSE-C 与 SSE-S3 的差异速览
这里先给一张简表,让你快速区分。后面的章节会详细展开。
| 特性 | SSE-C | SSE-S3 |
|---|---|---|
| 密钥管理方 | 客户 | AWS |
| 密钥存储位置 | 不在 S3 内存储(仅存 MD5 哈希) | AWS 内部自行管理 |
| 每次请求需携带密钥 | 是 | 否 |
| 支持的加密算法 | AES-256-CBC | AES-256-XTS(实际是 S3 内部实现) |
| 密钥轮换 | 手动重新上传对象 | 自动(可选) |