データベース暗号化は、データベース内のデータを保護するために使用される事前対策です。 データベース暗号化は、特権ユーザーによる平文ストレージまたはデータ盗難によって引き起こされるデータ漏洩を防ぐのに役立ちます。 データベース暗号化は、セキュリティ境界を突破する攻撃者からの防御にも役立ちます。 これにより、機密データリークによる問題の解決に役立ちます。 暗号化SDKを使用してクライアントで暗号化されたデータは、リレーショナルデータベースまたは非リレーショナルデータベースに格納できます。 このトピックでは、データベースの機密データ暗号化のシナリオと、データの暗号化と復号化の方法について説明します。 このトピックでは、データベースの機密データを暗号化する方法の例も示します。
シナリオ
データ侵害後の平文ストレージによる機密データ漏洩を防止します。
ほとんどの場合、データベース内のデータは平文で保存され、使用されます。 データファイルまたはバックアップファイルが開示されると、深刻なデータリークが発生する可能性があります。 データ侵害攻撃では、プレーンテキストで保存されたデータを保護できません。 この問題を解決するには、データを暗号化してデータ漏洩を防ぐ必要があります。
特権ユーザーによるデータ盗難による機密データ漏洩を防止します。
データベースの暗号化は、データベースの許可制御システムとは無関係である。 データベース暗号化は、権限制御の強化に役立ちます。 専用の暗号化システムを使用して、機密データに対するアクセス許可を設定できます。 これにより、データベーススーパーユーザーなどの特権ユーザーからの機密データへのアクセスを効果的に制御することで、データセキュリティが確保されます。
データの暗号化と復号化
暗号化
データキーを作成します。
暗号化SDKはGenerateDataKey操作を呼び出して、key Management Service (KMS) にデータキーを要求します。 KMSは、データキーと暗号化されたデータキーを返します。
データを暗号化して保存します。
データキーを使用してデータを暗号化し、Base64アルゴリズムを使用して暗号文をエンコードします。
Base64-encoded暗号文をデータベースに保存します。
解読
データの照会と復号化。
データベースからBase64-encoded暗号文を読み取ります。
Base64アルゴリズムを使用してBase64-encoded暗号文をデコードします。 暗号化SDKは、KMSのDecrypt操作を呼び出して、暗号化されたデータキーを復号します。 その後、KMSは解読されたデータキーを返します。
暗号文を復号化します。 暗号化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環境変数に保存されます。
認証情報の設定方法の詳細については、「アクセス資格情報の管理」をご参照ください。
環境変数を設定するために使用される方法は、オペレーティングシステムによって異なります。 詳細については、「Linux、macOS、およびWindowsでの環境変数の設定」をご参照ください。
エンティティクラスを定義します。
@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」をご参照ください。