閱讀452 返回首頁    go 小米 go MIUI米柚


通過客戶端加密保護數據__數據安全_最佳實踐_對象存儲 OSS-阿裏雲

客戶端加密是指用戶數據在發送給遠端服務器之前就完成加密,而加密所用的密鑰的明文隻保留在本地,從而可以保證用戶數據安全,即使數據泄漏別人也無法解密得到原始數據。

本文介紹如何基於OSS的現有Python SDK版本,通過客戶端加密來保護數據。

原理介紹

  1. 用戶本地維護一對RSA密鑰(rsa_private_keyrsa_public_key)。
  2. 每次上傳Object時,隨機生成一個AES256類型的對稱密鑰data_key,然後用data_key加密原始content得到encrypt_content。
  3. rsa_public_key加密data_key,得到encrypt_data_key,作為用戶的自定義meta放入請求頭部,和encrypt_content一起發送到OSS。
  4. Get Object時,首先得到encrypt_content以及用戶自定義meta中的encrypt_data_key
  5. 用戶使用rsa_private_key解密encrypt_data_key得到data_key,然後用data_key解密encrypt_content得到原始content。

注意:本文用戶的密鑰為非對稱的RSA密鑰, 加密object content時用的AES256-CTR算法, 詳情可參考PyCrypto Document。本文旨在介紹如何通過object的自定義meta來實現客戶端加密,至於加密密匙類型及加密算法,用戶可以根據自己的需要進行選擇。

架構圖

client-encrypt

準備工作

  1. Python SDK的安裝和使用,參考 Python SDK 快速安裝

  2. 安裝PyCrypto庫。

    1. pip install pycrypto

完整 Python 示例代碼

  1. # -*- coding: utf-8 -*-
  2. import os
  3. import shutil
  4. import base64
  5. import random
  6. import oss2
  7. from Crypto.Cipher import PKCS1_OAEP
  8. from Crypto.PublicKey import RSA
  9. from Crypto.Cipher import AES
  10. from Crypto import Random
  11. from Crypto.Util import Counter
  12. # aes 256, key always is 32 bytes
  13. _AES_256_KEY_SIZE = 32
  14. _AES_CTR_COUNTER_BITS_LEN = 8 * 16
  15. class AESCipher:
  16. def __init__(self, key=None, start=None):
  17. self.key = key
  18. self.start = start
  19. if not self.key:
  20. self.key = Random.new().read(_AES_256_KEY_SIZE)
  21. if not self.start:
  22. self.start = random.randint(1, 10)
  23. ctr = Counter.new(_AES_CTR_COUNTER_BITS_LEN, initial_value=self.start)
  24. self.cipher = AES.new(self.key, AES.MODE_CTR, counter=ctr)
  25. def encrypt(self, raw):
  26. return self.cipher.encrypt(raw)
  27. def decrypt(self, enc):
  28. return self.cipher.decrypt(enc)
  29. # 首先初始化AccessKeyId、AccessKeySecret、Endpoint等信息。
  30. # 通過環境變量獲取,或者把諸如“<您的AccessKeyId>”替換成真實的AccessKeyId等。
  31. #
  32. # 以杭州區域為例,Endpoint可以是:
  33. # https://oss-cn-hangzhou.aliyuncs.com
  34. # https://oss-cn-hangzhou.aliyuncs.com
  35. # 分別以HTTP、HTTPS協議訪問。
  36. access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID', '<您的AccessKeyId>')
  37. access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET', '<您的AccessKeySecret>')
  38. bucket_name = os.getenv('OSS_TEST_BUCKET', '<您的Bucket>')
  39. endpoint = os.getenv('OSS_TEST_ENDPOINT', '<您的訪問域名>')
  40. # 確認上麵的參數都填寫正確了
  41. for param in (access_key_id, access_key_secret, bucket_name, endpoint):
  42. assert '<' not in param, '請設置參數:' + param
  43. ##### 0 prepare ########
  44. # 0.1 生成rsa key文件並保存到disk
  45. rsa_private_key_obj = RSA.generate(2048)
  46. rsa_public_key_obj = rsa_private_key_obj.publickey()
  47. encrypt_obj = PKCS1_OAEP.new(rsa_public_key_obj)
  48. decrypt_obj = PKCS1_OAEP.new(rsa_private_key_obj)
  49. # save to local disk
  50. file_out = open("private_key.pem", "w")
  51. file_out.write(rsa_private_key_obj.exportKey())
  52. file_out.close()
  53. file_out = open("public_key.pem", "w")
  54. file_out.write(rsa_public_key_obj.exportKey())
  55. file_out.close()
  56. # 0.2 創建Bucket對象,所有Object相關的接口都可以通過Bucket對象來進行
  57. bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)
  58. obj_name = 'test-sig-1'
  59. content = "test content"
  60. #### 1 Put Object ####
  61. # 1.1 生成加密這個object所用的一次性的對稱密鑰 encrypt_cipher, 其中的key 和 start為隨機生成的value
  62. encrypt_cipher = AESCipher()
  63. # 1.2 將輔助解密的信息用公鑰加密後存到object的自定義meta中. 後續當我們get object時,就可以根據自定義meta,用私鑰解密得到原始content
  64. headers = {}
  65. headers['x-oss-meta-x-oss-key'] = base64.b64encode(encrypt_obj.encrypt(encrypt_cipher.key))
  66. headers['x-oss-meta-x-oss-start'] = base64.b64encode(encrypt_obj.encrypt(str(encrypt_cipher.start)))
  67. # 1.3. 用 encrypt_cipher 對原始content加密得到encrypt_content
  68. encryt_content = encrypt_cipher.encrypt(content)
  69. # 1.4 上傳object
  70. result = bucket.put_object(obj_name, encryt_content, headers)
  71. if result.status / 100 != 2:
  72. exit(1)
  73. #### 2 Get Object ####
  74. # 2.1 下載得到加密後的object
  75. result = bucket.get_object(obj_name)
  76. if result.status / 100 != 2:
  77. exit(1)
  78. resp = result.resp
  79. download_encrypt_content = resp.read()
  80. # 2.2 從自定義meta中解析出之前加密這個object所用的key 和 start
  81. download_encrypt_key = base64.b64decode(resp.headers.get('x-oss-meta-x-oss-key', ''))
  82. key = decrypt_obj.decrypt(download_encrypt_key)
  83. download_encrypt_start = base64.b64decode(resp.headers.get('x-oss-meta-x-oss-start', ''))
  84. start = int(decrypt_obj.decrypt(download_encrypt_start))
  85. # 2.3 生成解密用的cipher, 並解密得到原始content
  86. decrypt_cipher = AESCipher(key, start)
  87. download_content = decrypt_cipher.decrypt(download_encrypt_content)
  88. if download_content != content:
  89. print "Error!"
  90. else:
  91. print "Decrypt ok. Content is: %s" % download_content

最後更新:2016-11-23 16:04:11

  上一篇:go 通過crc64校驗數據傳輸的完整性__數據安全_最佳實踐_對象存儲 OSS-阿裏雲
  下一篇:go OssDemo簡介__安卓應用示例_最佳實踐_對象存儲 OSS-阿裏雲