基础加密操作:上传、下载与默认策略

上一章我们把 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-S3AWS/Azure 托管只需指定 ServerSideEncryption极小,服务端处理
SSE-KMSKMS 服务指定 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-C 的密钥建议存成 Base64 编码的字符串,不要存 Raw Bytes。否则在不同语言之间传递时容易出问题。密钥还有长度限制——AES256 要求 32 字节,多一个少一个都不行。

设置默认加密策略:一次配置,全局加密

如果你嫌每次上传都要加加密参数太麻烦,可以在存储桶上设置默认加密策略。这样所有新上传的对象都会自动加密。

设置方式分两种:

  • 服务端侧:直接在存储桶属性里设置默认 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 参数,就能在服务端完成重加密,不经过客户端。

三个操作的关系图

下面这张图我把上传加密、下载解密和默认策略放在一起,方便你理解它们之间的数据流和控制流:

基础加密操作流程图 上传加密对象 PutObject + SSE 参数 下载解密对象 GetObject + 相同密钥 默认加密策略 PutBucketEncryption 上传后 用此密钥解密 自动应用加密规则 关键要点 ① 默认策略只对新对象生效,存量对象需单独重加密 ② 下载时 SSE-C 密钥必须与上传时一致 ③ 性能调优前先搞清楚你用的是哪种加密方式 对象存储服务端 存储加密数据,解密后返回明文 加密数据写入 请求数据返回

实际操作中的三个常见坑

  1. 密钥碰撞:如果用 SSE-C 且密钥冲突或重复上传,旧版本被覆盖但没通知——我建议在上传前先判断对象是否存在,或者使用版本控制。
  2. 默认策略覆盖问题:如果你在客户端也传了加密参数,会覆盖默认策略。这有时候会导致合规失败,所以团队约定最好统一用服务端默认。
  3. 性能参数盲点:设置默认策略后,上传性能会受后端加密实现的影响。比如某些云厂商的 SSE-S3 有并行度限制,你可能需要调整 max_concurrency 来适配。
总结:上传加密对象、下载解密对象、设置默认加密策略,这三板斧是加密 SDK 最基础的能力。你不需要背代码,但需要理解每个操作背后的参数传递逻辑。下一章我们会基于这些基础操作,开始调优 SDK 的并发、缓冲和重试参数——到时候你会感谢自己把基础打扎实了。