すべてのプロダクト
Search
ドキュメントセンター

Key Management Service:データベースの機密データの暗号化

最終更新日:Jan 03, 2025

データベース暗号化は、データベース内のデータを保護するために使用される事前対策です。 データベース暗号化は、特権ユーザーによる平文ストレージまたはデータ盗難によって引き起こされるデータ漏洩を防ぐのに役立ちます。 データベース暗号化は、セキュリティ境界を突破する攻撃者からの防御にも役立ちます。 これにより、機密データリークによる問題の解決に役立ちます。 暗号化SDKを使用してクライアントで暗号化されたデータは、リレーショナルデータベースまたは非リレーショナルデータベースに格納できます。 このトピックでは、データベースの機密データ暗号化のシナリオと、データの暗号化と復号化の方法について説明します。 このトピックでは、データベースの機密データを暗号化する方法の例も示します。

シナリオ

  • データ侵害後の平文ストレージによる機密データ漏洩を防止します。

    ほとんどの場合、データベース内のデータは平文で保存され、使用されます。 データファイルまたはバックアップファイルが開示されると、深刻なデータリークが発生する可能性があります。 データ侵害攻撃では、プレーンテキストで保存されたデータを保護できません。 この問題を解決するには、データを暗号化してデータ漏洩を防ぐ必要があります。

  • 特権ユーザーによるデータ盗難による機密データ漏洩を防止します。

    データベースの暗号化は、データベースの許可制御システムとは無関係である。 データベース暗号化は、権限制御の強化に役立ちます。 専用の暗号化システムを使用して、機密データに対するアクセス許可を設定できます。 これにより、データベーススーパーユーザーなどの特権ユーザーからの機密データへのアクセスを効果的に制御することで、データセキュリティが確保されます。

データの暗号化と復号化

  • 暗号化

    1. データキーを作成します。

      暗号化SDKはGenerateDataKey操作を呼び出して、key Management Service (KMS) にデータキーを要求します。 KMSは、データキーと暗号化されたデータキーを返します。

    2. データを暗号化して保存します。

      1. データキーを使用してデータを暗号化し、Base64アルゴリズムを使用して暗号文をエンコードします。

      2. Base64-encoded暗号文をデータベースに保存します。

  • 解読

    データの照会と復号化。

    1. データベースからBase64-encoded暗号文を読み取ります。

    2. Base64アルゴリズムを使用してBase64-encoded暗号文をデコードします。 暗号化SDKは、KMSのDecrypt操作を呼び出して、暗号化されたデータキーを復号します。 その後、KMSは解読されたデータキーを返します。

    3. 暗号文を復号化します。 暗号化SDKは、データキーを使用して暗号文を復号し、平文を取得します。

暗号化SDKは、アプリケーションからデータベースに送信するデータを暗号化します。 KMSはデータキーを生成および管理します。

次のサンプルコードは、Spring Data JPAまたはPythonを使用してUserテーブルの電子メールフィールドを暗号化および復号化する方法の例を示しています。 これらの例では、電子メールフィールドは、復号化中にキャッシュされるデータキーを使用する。 電子メールフィールドを複数回クエリする場合は、キャッシュされたデータキーを使用できます。

電子メールフィールドに暗号化されたデータを格納できるようにするには、電子メールフィールドのサイズを元のサイズの3倍に増やす必要があります。

Spring Data JPAのサンプルコード

説明

Alibaba CloudアカウントのAccessKeyペアには、すべてのAPI操作に対する権限があります。 AccessKeyペアを使用して操作を実行することは、リスクの高い操作です。 RAMユーザーを使用してAPI操作を呼び出したり、ルーチンのO&Mを実行することを推奨します。プロジェクトコードにAccessKey IDとAccessKey Secretを保存しないことを推奨します。 そうしないと、AccessKeyペアが漏洩し、アカウントに属するすべてのリソースのセキュリティが侵害される可能性があります。

この例では、AccessKeyペアは、ID認証を実装するためにALIBABA_CLOUD_ACCESS_KEY_IDとALIBABA_CLOUD_ACCESS_KEY_SECRET環境変数に保存されます。

  • エンティティクラスを定義します。

    @Entity
    public class User {
        @Id
        @GeneratedValue
        private Long id;
    
        private String name;
        private String email;
    
        // getters and setters ...
    }
  • UserRepositoryクラスを定義します。

    public interface UserRepository extends CrudRepository<User, Long> {
     }
  • Spring Data JPAのAttributeConverterインターフェイスを実装します。

    EncryptionConverterクラスは、Encryption SDKを使用してデータキーを取得し、そのデータキーを使用して指定されたデータを暗号化および復号化します。

    @Converter
     public class EncryptionConverter implements AttributeConverter<String, String> {
         private static String ACCESS_KEY_ID = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
         private static String ACCESS_KEY_SECRET = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
         private static String CMK_ARN = "acs:kms:RegionId:UserId:key/CmkId";
         private static AliyunConfig config;
         static {
             config = new AliyunConfig();
             config.withAccessKey(ACCESS_KEY_ID, ACCESS_KEY_SECRET);
         }
     
         @Override
         public String convertToDatabaseColumn(String plainText) {
             BaseDataKeyProvider dataKeyProvider = new DefaultDataKeyProvider(CMK_ARN);
             AliyunCrypto crypto = new AliyunCrypto(config);
     
             try {
                 CryptoResult<byte[]> encryptResult = crypto.encrypt(dataKeyProvider, plainText.getBytes(StandardCharsets.UTF_8), Collections.singletonMap("sample", "context"));
                 return Base64.getEncoder().encodeToString(encryptResult.getResult());
             } catch (InvalidAlgorithmException e) {
                 System.out.println("Failed.");
                 System.out.println("Error message: " + e.getMessage());
             }
             return null;
         }
     
         @Override
         public String convertToEntityAttribute(String cipherText) {
             BaseDataKeyProvider dataKeyProvider = new DefaultDataKeyProvider(CMK_ARN);
             AliyunCrypto crypto = new AliyunCrypto(config);
             // *** Cache a customer master key (CMK) ***
             CryptoKeyManager ckm = new CachingCryptoKeyManager(new LocalDataKeyMaterialCache());
             crypto.setCryptoKeyManager(ckm);
             try {
                 CryptoResult<byte[]> decryptResult = crypto.decrypt(dataKeyProvider, Base64.getDecoder().decode(cipherText));
                 return new String(decryptResult.getResult(), StandardCharsets.UTF_8);
             } catch (InvalidAlgorithmException | UnFoundDataKeyException e) {
                 e.printStackTrace();
             }
             return null;
         }
     }
  • @ Convertアノテーションを追加します。

    暗号化が必要な属性に @ Convertアノテーションを追加します。 属性はデータベース内の列です。

    @Entity
     public class User {
         @Id
         @GeneratedValue
         private Long id;
     
         private String name;
         @Convert(converter = EncryptionConverter.class)
         private String email;
         
         // getters and setters ...
     }

Pythonのサンプルコード

  • オブジェクトを定義します。

    class User(object):
         def get_name(self):
             return self.name
     
         def set_name(self, value):
             self.name = value
     
         def get_email(self):
             return self.email
     
         def set_email(self, value):
             self.email = value
  • データベース内のデータを管理するための関数を実装します。

    def user_add(user):
         # Connect to the database. 
         conn = db_connection()
         # Obtain a cursor object that can be used to execute an SQL statement and return the result as a dictionary. 
         cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
         # Specify the SQL statement that you want to execute. 
         sql = 'insert into user(name, email) values(%s,%s);'
         # Execute the SQL statement. 
         cursor.execute(sql, [user.name, user.email])
         print("insert name: " + user.name)
         print("insert email: " + user.email)
         # Commit the write operation. 
         conn.commit()
         last_id = cursor.lastrowid
         # Close the cursor object. 
         cursor.close()
         # Close the database connection. 
         conn.close()
         return last_id
     
     
     def user_select_by_id(id):
         # Connect to the database. 
         conn = db_connection()
         # Obtain a cursor object that can be used to execute an SQL statement and return the result as a dictionary. 
         cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
         # Specify the SQL statement that you want to execute. 
         sql = 'select * from user where id = %s;'
         # Execute the SQL statement. 
         cursor.execute(sql, [id])
         result = cursor.fetchone()
         print("select result: " + str(result))
         user = User()
         user.__dict__ = result
         # Close the cursor object. 
         cursor.close()
         # Close the database connection. 
         conn.close()
         return user
  • データの暗号化と復号化のデコレータを実装します。

    def enc_convert():
         def enc_(func):
             def wrapper(self, plain_text):
                 provider = DefaultDataKeyProvider(AES_KEY_ARN)
                 client = build_aliyun_crypto(False)
                 cipher_text, enc_material = client.encrypt(provider, plain_text.encode("utf-8"), ENCRYPTION_CONTEXT)
                 cipher_text_str = base64.standard_b64encode(cipher_text).decode("utf-8")
                 f = func(self, cipher_text_str)
                 return f
     
             return wrapper
     
         return enc_
     
     
     def dec_convert(column_name):
         def dec_(func):
             def wrapper(self):
                 user = self.__dict__
                 cipher_text = user.get(column_name)
                 cipher_text_bytes = base64.standard_b64decode(cipher_text.encode("utf-8"))
                 provider = DefaultDataKeyProvider(AES_KEY_ARN)
                 client = build_aliyun_crypto(False)
                 plain_text, dec_material = client.decrypt(provider, cipher_text_bytes)
                 user[column_name] = bytes.decode(plain_text)
                 result = User()
                 result.__dict__ = user
                 f = func(result)
                 return f
     
             return wrapper
     
         return dec_
  • 暗号化する電子メールフィールドにデコレータを追加します。

    class User(object):
         def get_name(self):
             return self.name
     
         def set_name(self, value):
             self.name = value
     
         @dec_convert(column_name="email")
         def get_email(self):
             return self.email
     
         @enc_convert()
         def set_email(self, value):
             self.email = value

データベースの機密データを暗号化する方法の詳細については、「alibabacloud-encryption-sdk-java」および「alibabacloud-encryption-sdk-python」をご参照ください。