OSS客戶端加密是在數據上傳至OSS之前,由用戶在本地對數據進行加密處理,確保只有密鑰持有者才能解密數據,增強數據在傳輸和存儲過程中的安全性。
免責聲明
使用客戶端加密功能時,您需要對主密鑰的完整性和正確性負責。因您維護不當導致主密鑰用錯或丟失,從而導致加密數據無法解密所引起的一切損失和后果均由您自行承擔。
在對加密數據進行復制或者遷移時,您需要對加密元數據的完整性和正確性負責。因您維護不當導致加密元數據出錯或丟失,從而導致加密數據無法解密所引起的一切損失和后果均由您自行承擔。
使用場景
高度敏感數據:對于包含極高敏感度信息的數據,如個人身份信息(PII)、金融交易記錄、醫療健康數據等,用戶可能希望在數據離開本地環境之前就對其進行加密處理,確保即使數據在傳輸過程中被截獲,原始數據仍能得到有效保護。
合規要求:某些行業和法規(例如HIPAA、GDPR等)要求對存儲在第三方平臺上的數據進行嚴格的加密控制,客戶端加密能夠滿足這些合規性要求,因為密鑰由用戶自己管理,不通過網絡傳遞,也不由云服務商直接掌握。
更強的自主控制權:企業或者開發者可能希望對加密過程有完全的控制權,包括選擇加密算法、管理和輪換密鑰。通過客戶端加密,可以實現這一目標,確保只有合法授權的用戶才能解密和訪問數據。
跨區域數據遷移安全性:在將數據從一個地區遷移到另一個地區的過程中,使用客戶端加密可以在數據遷移前后保持數據始終處于加密狀態,增強了數據在公網傳輸的安全性。
注意事項
本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地域的其他阿里云產品訪問OSS,請使用內網Endpoint。關于OSS支持的Region與Endpoint的對應關系,請參見OSS地域和訪問域名。
本文以從環境變量讀取訪問憑證為例。如何配置訪問憑證,請參見配置訪問憑證。
本文以OSS域名新建OSSClient為例。如果您希望通過自定義域名、STS等方式新建OSSClient,請參見初始化。
背景信息
使用客戶端加密時,會為每個Object生成一個隨機數據加密密鑰,用該隨機數據加密密鑰明文對Object的數據進行對稱加密。主密鑰用于生成隨機的數據加密密鑰,加密后的內容會作為Object的meta信息保存在服務端。解密時先用主密鑰將加密后的隨機密鑰解密出來,再用解密出來的隨機數據加密密鑰明文解密Object的數據。主密鑰只參與客戶端本地計算,不會在網絡上進行傳輸或保存在服務端,以保證主密鑰的數據安全。
加密方式
對于主密鑰的使用,目前支持如下兩種方式:
使用KMS托管用戶主密鑰
當使用KMS托管用戶主密鑰用于客戶端數據加密時,需要將KMS用戶主密鑰ID(即CMK ID)傳遞給SDK。
使用用戶自主管理的主密鑰(RSA)
主密鑰信息由用戶提供,需要用戶將主密鑰的公鑰、私鑰信息作為參數傳遞給SDK。
使用以上兩種加密方式能夠有效地避免數據泄漏,保護客戶端數據安全。即使數據泄漏,其他人也無法解密得到原始數據。
關于客戶端加密的更多信息,請參見開發指南中的客戶端加密。
V2版本客戶端加密(推薦)
客戶端加密支持分片上傳超過5 GB的文件。在使用分片方式上傳文件時,需要指定上傳文件的總大小和分片大小, 除了最后一個分片外,每個分片的大小要一致,且分片大小目前必須是16的整數倍。
調用客戶端加密上傳文件后,加密元數據會被保護,無法通過CopyObject等接口修改加密相關元數據信息。
加密元數據
參數
描述
是否必需
x-oss-meta-client-side-encryption-key
加密后的密鑰。 經過RSA或KMS加密后再經過base64編碼的字符串。
是
x-oss-meta-client-side-encryption-start
隨機產生的加密數據的初始向量 。經過RSA或KMS加密后再經過base64編碼的字符串。
是
x-oss-meta-client-side-encryption-cek-alg
數據的加密算法。
是
x-oss-meta-client-side-encryption-wrap-alg
數據密鑰的加密算法。
是
x-oss-meta-client-side-encryption-matdesc
內容加密密鑰(CEK)描述,JSON格式。
否
x-oss-meta-client-side-encryption-unencrypted-content-length
加密前的數據長度。如未指定content-length,則不生成該參數。
否
x-oss-meta-client-side-encryption-unencrypted-content-md5
加密前的數據的MD5。如未指定MD5,則不生成該參數。
否
x-oss-meta-client-side-encryption-data-size
分片上傳文件的總大小。
否(分片上傳時必須指定)
x-oss-meta-client-side-encryption-part-size
分片上傳中每個part的大小。
否(分片上傳時必須指定)
創建加密Bucket
同普通上傳、下載等操作一樣,在使用客戶端加密上傳、下載文件之前需要先初始化Bucket實例。通過Bucket實例的上傳、下載等接口進行文件的上傳、下載操作。客戶端加密通過CryptoBucket這個類繼承了普通Bucket的接口,需要使用到客戶端加密時,只需要傳入相應的參數,同初始化Bucket實例一樣,初始化一個類似的CryptoBucket實例即可。
初始化非對稱加密主密鑰方式(RSA)的Bucket
重要使用RSA加密方式時,需要您自己管理加密的密鑰對,一旦丟失密鑰或者密鑰數據出現損壞,可能會導致數據無法解密,推薦使用KMS托管方式進行加密。如果由于業務場景一定要使用RSA加密方式,建議您做好密鑰數據的備份。
初始化非對稱加密主密鑰方式(RSA)的Bucket示例代碼如下:
# -*- coding: utf-8 -*- import os import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider from oss2.crypto import RsaProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 只使用解密功能。 # key_pair = {'private_key': 'yourPrivateKey'} # 只使用加密功能。 # key_pair = {'public_key': 'yourPublicKey'} # 同時使用加密和解密功能。 key_pair = {'private_key': 'yourPrivateKey', 'public_key': 'yourPublicKey'} # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # yourBucketName填寫存儲空間名稱。 bucket = oss2.CryptoBucket(auth, endpoint, 'yourBucketName', crypto_provider=RsaProvider(key_pair), region=region)
初始化KMS主密鑰加密方式的Bucket
初始化KMS主密鑰加密方式的Bucket的示例代碼如下:
# -*- coding: utf-8 -*- import os import oss2 from oss2.crypto import AliKMSProvider from oss2.credentials import EnvironmentVariableCredentialsProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) kms_provider = AliKMSProvider(auth, 'yourRegion', 'yourCMKID') # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # yourBucketName填寫存儲空間名稱。 bucket = oss2.CryptoBucket(auth, endpoint, 'yourBucketName', crypto_provider=kms_provider, region=region)
使用和管理多個密鑰
對于同一個bucket,您在上傳或者下載不同的數據時,可能會使用不同的密鑰進行加密。您可以給不同的密鑰配置不同的描述信息,并將這些密鑰和描述信息添加到bucket的加密信息中,待您再解密數據時,SDK內部會根據加密數據的描述信息自動匹配密鑰,從而實現數據無縫解密。示例代碼如下:
# -*- coding: utf-8 -*- import os import oss2 from oss2.crypto import RsaProvider from oss2.credentials import EnvironmentVariableCredentialsProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 創建一個RSA密鑰對。 key_pair_1 = {'private_key': 'yourPrivateKey_1', 'public_key': 'yourPublicKey_1'} mat_desc_1 = {'key1': 'value1'} # 創建另一個RSA密鑰對。 key_pair_2 = {'private_key': 'yourPrivateKey_2', 'public_key': 'yourPublicKey_2'} mat_desc_2 = {'key2': 'value2'} provider = RsaProvider(key_pair=key_pair_2, mat_desc=mat_desc_2) # 將key_pair_1的描述信息添加到provider。 encryption_materials = oss2.EncryptionMaterials(mat_desc_1, key_pair=key_pair_1) provider.add_encryption_materials(encryption_materials) # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # 使用provider初始化crypto_bucket,這樣可以使用crypto_bucket下載使用描述信息為mat_desc_1的主密鑰加密的對象數據。 crypto_bucket = oss2.CryptoBucket(auth, endpoint, 'yourBucketName', crypto_provider=provider, region=region)
普通上傳和下載文件
使用主密鑰KMS普通上傳和下載文件的示例代碼如下:
# -*- coding: utf-8 -*- import os import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider from oss2.crypto import RsaProvider from oss2.cryptoimportAliKMSProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) kms_provider = AliKMSProvider(auth, 'yourRegion', 'yourCMKID') # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" bucket = oss2.CryptoBucket(auth, endpoint, 'yourBucketName', crypto_provider=kms_provider, region=region) key = 'motto.txt' content = b'a' * 1024 * 1024 filename = 'download.txt' # 上傳文件。 bucket.put_object(key, content, headers={'content-length': str(1024 * 1024)}) # 下載OSS文件到本地內存。 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
分片上傳
說明分片上傳文件時,一旦上傳中斷(進程退出)后,加密分片上傳上下文可能會丟失。上傳中斷后如果要繼續上傳該文件,則必須再次上傳整個文件。
推薦您直接使用OSS封裝好的斷點續傳上傳接口上傳大文件,該接口已將加密分片上傳上下文保存在用戶本地了,即使是上傳出現中斷,該上下文信息也不會丟失。
使用主密鑰KMS分片上傳文件示例代碼如下:
# -*- coding: utf-8 -*- import os import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider from oss2.crypto import RsaProvider from oss2.cryptoimportAliKMSProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) kms_provider = AliKMSProvider(auth, 'yourRegion', 'yourCMKID') # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" bucket = oss2.CryptoBucket(auth, endpoint, 'yourBucketName', crypto_provider = kms_provider, region=region) """ 分片上傳 """ # 初始化上傳分片。 part_a = b'a' * 1024 * 100 part_b = b'b' * 1024 * 100 part_c = b'c' * 1024 * 100 multi_content = [part_a, part_b, part_c] parts = [] data_size = 100 * 1024 * 3 part_size = 100 * 1024 multi_key = "test_crypto_multipart" # 初始化加密分片上傳上下文。 context = models.MultipartUploadCryptoContext(data_size, part_size) res = bucket.init_multipart_upload(multi_key, upload_context=context) upload_id = res.upload_id # 分片上傳示例中使用順序上傳,實際使用中為了加快上傳速度也可以支持多個線程并發上傳。 for i in range(3): # context的值不允許修改,否則將導致數據上傳失敗。 result = bucket.upload_part(multi_key, upload_id, i + 1, multi_content[i], upload_context=context) parts.append(oss2.models.PartInfo(i + 1, result.etag, size=part_size, part_crc=result.crc)) # 完成分片上傳。 result = bucket.complete_multipart_upload(multi_key, upload_id, parts) # 驗證獲取到的文件內容跟上傳時的文件內容是否一致。 result = bucket.get_object(multi_key) content_got = b'' for chunk in result: content_got += chunk assert content_got[0:102400] == part_a assert content_got[102400:204800] == part_b assert content_got[204800:307200] == part_c
斷點續傳上傳
使用主密鑰RSA斷點續傳上傳文件示例代碼如下:
# -*- coding: utf-8 -*- import os import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider from oss2.crypto import RsaProvider key = 'motto.txt' content = b'a' * 1024 * 1024 * 100 file_name_put = 'upload.txt' # 將content的內容寫入文件。 with open(file_name_put, 'wb') as fileobj: fileobj.write(content) # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 創建存儲空間,使用用戶自主管理(RSA)方式加密,此方式只支持文件整體上傳、下載操作。 # 如果您使用2.9.0及以上版本的SDK,不建議使用LocalRsaProvider初始化bucket。 # bucket = oss2.CryptoBucket(auth,'yourEndpoint', 'yourBucketName', crypto_provider=LocalRsaProvider()) # 只使用解密功能。 # key_pair = {'private_key': 'yourPrivateKey'} # 只使用加密功能。 # key_pair = {'public_key': 'yourPublicKey'} # 同時使用加密和解密功能。 key_pair = {'private_key': 'yourPrivateKey', 'public_key': 'yourPublicKey'} # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # 初始化bucket將upload_contexts_flag設置為True,調用upload_part接口不用傳入加密分片上傳上下文參數。 bucket = oss2.CryptoBucket(auth, endpoint, 'yourBucketName', crypto_provider=RsaProvider(key_pair), region=region) # 為演示方便,本示例將multipart_threshold的值設置為10*1024*1024,默認值為10 MB。實際使用過程中可以根據使用場景靈活設置。 # multipart_threshold表示文件超過這個閾值就是用分片上傳方式上傳問題,如果文件大小小于這個值,建議使用簡單的put_object接口上傳文件。 # part_size為使用分片上傳時分片的大小,默認值為10 MB。 # num_threads為并發上傳線程的個數,默認值為1。 oss2.resumable_upload(bucket, key, file_name_put, multipart_threshold=10 * 1024 * 1024, part_size=1024 * 1024, num_threads=3)
斷點續傳下載
使用主密鑰KMS斷點續傳下載文件示例代碼如下:
# -*- coding: utf-8 -*- import os import oss2 from oss2.crypto import RsaProvider from oss2.cryptoimportAliKMSProvider from oss2.credentials import EnvironmentVariableCredentialsProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) key = 'motto.txt' content = b'a' * 1024 * 1024 * 100 file_name_get = 'download.txt' kms_provider = AliKMSProvider(auth, 'yourRegion', 'yourCMKID') endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" bucket = oss2.CryptoBucket(auth, endpoint, 'yourBucketName', crypto_provider=kms_provider, region=region) # 斷點續傳下載。 oss2.resumable_download(bucket, key, file_name_get, multiget_threshold=10 * 1024 * 1024, part_size=1024 * 1024, num_threads=3) # 驗證獲取到的文件內容跟上傳時的文件內容是否一致。 with open(file_name_get, 'rb') as fileobj: assert fileobj.read() == content
V1版本客戶端加密(不推薦)
V1版本的客戶端加密只支持通過PutObject接口上傳5 GB以下的文件,不支持分片上傳、斷點續傳上傳和斷點續傳下載接口。
通過客戶端加密接口上傳文件后,不允許通過CopyObject等接口修改對象的加密元數據。如果修改了這些元數據,可能會導致數據無法解密。
V1版本的客戶端加密僅在Python SDK上支持,其它語言的SDK無法解密通過V1版本客戶端加密上傳的數據。
自2.11.0版本后開始支持V2版本的客戶端加密,V2版本支持的功能更加完善,條件允許的情況下建議升級到新版本。
加密元數據
參數
描述
是否必需
x-oss-meta-oss-crypto-key
加密后的密鑰。 經過RSA加密后再經過base64編碼的字符串。
是
x-oss-meta-oss-crypto-start
隨機產生的加密數據的初始值 。經過RSA加密后再經過base64編碼的字符串。
是
x-oss-meta-oss-cek-alg
數據的加密算法。
是
x-oss-meta-oss-wrap-alg
數據密鑰的加密算法。
是
x-oss-meta-oss-matdesc
內容加密密鑰(CEK)描述,JSON格式。暫未生效。
否
x-oss-meta-unencrypted-content-length
加密前的數據長度。如未指定content-length則不生成該參數。
否
x-oss-meta-unencrypted-content-md5
加密前的數據的MD5。如未指定MD5則不生成該參數。
否
使用RSA方式上傳和下載文件
使用RSA方式上傳和下載文件示例代碼如下:
# -*- coding: utf-8 -*- import os import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider from oss2.crypto import LocalRsaProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # 創建存儲空間,使用用戶自主管理(RSA)方式加密,此方式只支持文件整體上傳下載操作。 bucket = oss2.CryptoBucket(auth, endpoint, 'yourBucketName', crypto_provider=LocalRsaProvider(), region=region) key = 'motto.txt' content = b'a' * 1024 * 1024 filename = 'download.txt' # 上傳文件。 bucket.put_object(key, content, headers={'content-length': str(1024 * 1024)}) # 下載OSS文件到本地內存。 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
相關文檔
關于客戶端加密的完整示例代碼,請參見GitHub示例。