基础加密操作:上传、下载与默认策略
上一章我们把 SDK 环境搭起来了,也跑了第一个加密对象上传。这一章我们深入三个最基础的操作——上传加密对象、下载解密对象、设置默认加密策略。这三个操作用得最多,也是调试性能参数的起点。
我个人的习惯是,先理解每个操作在 SDK 里对应什么参数,然后再去调优。原因很简单——你连默认怎么跑都不清楚,调优就是瞎调。
上传加密对象:不只是 PutObject
上传一个加密对象,本质上还是调用 PutObject。加密参数要么加在请求头里(SSE-C),要么由服务端自动处理(SSE-S3/KMS)。
看一段 Python SDK 的示例:
import boto3
s3 = boto3.client('s3',
aws_access_key_id='AKID',
aws_secret_access_key='Secret')
# 使用 SSE-C,自己带密钥
s3.put_object(
Bucket='my-bucket',
Key='encrypted-file.txt',
Body=b'Hello, world!',
SSECustomerAlgorithm='AES256',
SSECustomerKey='MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA='
)
嗯,这里要注意:SSECustomerKey 必须是 Base64 编码的 32 字节密钥。我曾经在线上环境遇到过同事把明文密钥直接传进去,结果接口返回 400。排查了半天,最后发现是忘记编码了。
上传加密对象的三种方式对比:
| 加密方式 | 密钥由谁管理 | 是否需要额外参数 | 性能影响 |
|---|---|---|---|
| SSE-S3 | AWS/Azure 托管 | 只需指定 ServerSideEncryption | 极小,服务端处理 |
| SSE-KMS | KMS 服务 | 指定 ServerSideEncryption + SSEKMSKeyId | 稍大,每次加密调用 KMS API |
| SSE-C | 用户自己 | 提供算法 + 密钥 | 由客户端计算,无额外 API |
你想想看,如果并发上传 1000 个小对象,SSE-KMS 可能会因为 KMS 限流造成延迟。这就是为什么后面调试性能参数时,我会建议根据场景选择合适的加密方式。
下载解密对象:反向操作,但细节不同
下载时 SDK 会自动解密——前提是你传对了参数。对于 SSE-C,下载时也必须提供同样的密钥:
response = s3.get_object(
Bucket='my-bucket',
Key='encrypted-file.txt',
SSECustomerAlgorithm='AES256',
SSECustomerKey='MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA='
)
data = response['Body'].read()
print(data) # 输出 b'Hello, world!'
注意,SSECustomerKey 必须和上传时一模一样。不一致会返回 400 BadRequest,错误信息是「The request signature we calculated does not match the signature you provided」——其实根本原因是密钥不匹配。我遇到过最奇葩的 case:有人把密钥中的字符 + 没做 URL 编码,直接导致签名失败。
设置默认加密策略:一次配置,全局加密
如果你嫌每次上传都要加加密参数太麻烦,可以在存储桶上设置默认加密策略。这样所有新上传的对象都会自动加密。
设置方式分两种:
- 服务端侧:直接在存储桶属性里设置默认 SSE 规则。这是最推荐的方式,适合团队统一规范。
- 客户端侧:在创建 S3 Client 时传入默认加密参数。适合临时环境或测试。
代码示例(服务端侧通过 SDK 设置):
s3.put_bucket_encryption(
Bucket='my-bucket',
ServerSideEncryptionConfiguration={
'Rules': [
{
'ApplyServerSideEncryptionByDefault': {
'SSEAlgorithm': 'AES256', # SSE-S3
# 如果是 KMS,可以加 'KMSMasterKeyID': 'key-id'
}
}
]
}
)
设置完后,你再上传对象时不需要传任何加密参数——服务端会自动加密。这就是「默认」的含义。但要注意:默认策略只对新上传的对象生效,对已存在的对象无效。
我曾经在项目上线前没注意这个细节,以为改策略后所有旧对象也会被加密,结果合规检查时发现一批历史数据是明文存储……所以如果你有存量数据,记得单独做一遍批量加密。
put_bucket_encryption 配合 CopyObject 来实现批量重写加密——源和目标是同一个 Key,设置不同的 SSE 参数,就能在服务端完成重加密,不经过客户端。
三个操作的关系图
下面这张图我把上传加密、下载解密和默认策略放在一起,方便你理解它们之间的数据流和控制流:
实际操作中的三个常见坑
- 密钥碰撞:如果用 SSE-C 且密钥冲突或重复上传,旧版本被覆盖但没通知——我建议在上传前先判断对象是否存在,或者使用版本控制。
- 默认策略覆盖问题:如果你在客户端也传了加密参数,会覆盖默认策略。这有时候会导致合规失败,所以团队约定最好统一用服务端默认。
- 性能参数盲点:设置默认策略后,上传性能会受后端加密实现的影响。比如某些云厂商的 SSE-S3 有并行度限制,你可能需要调整
max_concurrency来适配。