客户端加密是指将数据发送到OSS之前在用户本地进行加密。

免责声明

  • 使用客户端加密功能时,您需要对主密钥的完整性和正确性负责。因您维护不当导致主密钥用错或丢失,从而导致加密数据无法解密所引起的一切损失和后果均由您自行承担。
  • 在对加密数据进行复制或者迁移时,您需要对加密元信息的完整性和正确性负责。因您维护不当导致加密元信息出错或丢失,从而导致加密数据无法解密所引起的一切损失和后果均由您自行承担。

背景信息

使用客户端加密时,会为每个Object生成一个随机密钥,用该随机密钥对Object的数据进行对称加密。主密钥用于对该随机的对称密钥进行加密,加密后的内容会当作Object的meta信息保存在服务端。解密时先用主密钥将加密后的随机密钥解密出来,再用解密出来的随机密钥解密Object的数据。主密钥只参与客户端本地计算,不会在网络上进行传输或保存在服务端,以保证主密钥的数据安全。

注意
  • 客户端加密当前只支持5GB以下的文件。
  • 调用客户端加密上传文件后,不允许再调用Python SDK的update_object_meta接口或CopyObject修改object meta信息。

加密方式

对于主密钥的使用,目前支持如下两种方式:

  • 使用KMS托管用户主密钥

    当使用KMS托管用户主密钥用于客户端数据加密时,需要将KMS用户主密钥ID(即CMK ID)传递给SDK。

  • 使用用户自主管理的主密钥(RSA)

    主密钥信息由用户提供,需要用户将主密钥的公钥、私钥信息当做参数传递给SDK。

使用以上两种加密方式能够有效地避免数据泄漏,保护客户端数据安全。即使数据泄漏,其他人也无法解密得到原始数据。

客户端加密详细信息请参见开发指南中的客户端加密。完整的示例代码请参见GitHub

加密元信息

参数 描述 是否必需
x-oss-meta-oss-crypto-key 加密后的密钥。 经过RSA加密后再经过base64编码的字符串。
x-oss-meta-oss-crypto-start 随机产生的加密数据的初始值 。经过RSA加密后再经过base64编码的字符串。
x-oss-meta-oss-cek-alg 数据的加密算法,取值为AES/GCM/NoPadding。
x-oss-meta-oss-wrap-alg 数据密钥的加密算法。取值为rsa和kms。
x-oss-meta-oss-matdesc 内容加密密钥(CEK)描述,JSON格式。暂未生效。
x-oss-meta-unencrypted-content-length 加密前的数据长度。如未指定content-length则不生成该参数。
x-oss-meta-unencrypted-content-md5 加密前的数据的MD5。如未指定MD5则不生成该参数。

使用用户自主管理方式上传和下载文件

您可以使用用户自主管理方式上传和下载文件。代码如下:

# -*- coding: utf-8 -*-
import os
import oss2
from  oss2.crypto import LocalRsaProvider

# 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')

# 创建存储空间,使用用户自主管理(RSA)方式加密,此方式只支持文件整体上传下载操作。
bucket = oss2.CryptoBucket(auth,'<yourEndpoint>', '<yourBucketName>', crypto_provider=LocalRsaProvider())

key = 'motto.txt'
content = b'a' * 1024 * 1024
filename = 'download.txt'


# 上传文件
bucket.put_object(key, content, headers={'content-length': str(1024 * 1024)})

# 下载文件
result = bucket.get_object(key)

# 验证
content_got = b''
for chunk in result:
    content_got += chunk
assert content_got == content

# 下载OSS文件到本地文件
result = bucket.get_object_to_file(key, filename)

# 验证
with open(filename, 'rb') as fileobj:
    assert fileobj.read() == content

os.remove(filename)
			

使用KMS托管方式上传和下载文件

  • 前提条件
    1. 已开通阿里云密钥管理服务。
    2. 已生成您所在地域的密钥ID。
    3. 已创建自定义授权策略(操作路径:控制台 > 访问控制 > 策略管理 > 自定义授权策略 > 新建授权策略),并为对应用户关联此策略。

    参考以下格式创建自定义策略:

    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "kms:CreateKey",
            "kms:GenerateDataKey",
            "kms:ListKeys",
            "kms:Encrypt",
            "kms:Decrypt"
          ],
          "Resource": [
            "acs:kms:<yourRegion>:<yourloginUserId>:key/*"
          ]
        }
      ]
    }
    					
  • 示例代码
    # -*- coding: utf-8 -*-
    import os
    import oss2
    from  oss2.crypto import AliKMSProvider
    
    # 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
    auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
    
    # 创建存储空间,使用KMS托管方式加密,此方式只支持文件整体上传下载操作。
    bucket = oss2.CryptoBucket(auth,'<yourEndpoint>', 'liusiman123456',crypto_provider=AliKMSProvider('<yourAccessKeyId>', '<yourAccessKeySecret>', '<yourRegion>', '<yourCMK>', '1234'))
    
    key = 'motto.txt'
    content = b'a' * 1024 * 1024
    filename = 'download.txt'
    
    # 上传文件
    bucket.put_object(key, content, headers={'content-length': str(1024 * 1024)})
    
    # 下载文件
    result = bucket.get_object(key)
    
    # 验证
    content_got = b''
    for chunk in result:
        content_got += chunk
    assert content_got == content
    
    # 下载OSS文件到本地文件
    result = bucket.get_object_to_file(key, filename)
    
    # 验证
    with open(filename, 'rb') as fileobj:
        assert fileobj.read() == content
    
    os.remove(filename)