ApsaraDB RDS for MySQL、ApsaraDB RDS for PostgreSQL、PolarDB for MySQL、または PolarDB for PostgreSQL データベースのテーブル内の機密データ列を暗号化した後、EncJDBC ドライバーを使用して Java アプリケーションからデータベースに接続し、これらの暗号化された列のプレーンテキストデータにアクセスできます。このトピックでは、EncJDBC を使用してデータベースに接続し、暗号化された列のプレーンテキストデータにアクセスする方法について説明します。
前提条件
ターゲットデータベースに対して列暗号化が構成されており、ターゲットデータベースアカウントに [暗号文権限 (JDBC 復号)] 権限が付与されています。データベースの列暗号化を構成する方法とアカウント権限の詳細については、「データベースの列暗号化を構成する」をご参照ください。
エンドポイント、ポート、データベース名、データベースアカウント、パスワードなど、暗号化されたデータベースの接続情報を取得済みであること。
背景情報
列暗号化機能を使用すると、データベース内の特定の列を暗号化してデータセキュリティを向上させることができます。暗号化されたデータは、データベースに暗号文として保存されます。ただし、承認されたクライアントは、暗号文を透過的に復号してプレーンテキストデータにアクセスできます。
Alibaba Cloud は、Java プログラミング言語用の常時暗号化クライアントドライバー EncJDBC を提供しています。クライアントでドライバーを使用してデータベースに接続し、データベース接続 URL でマスター暗号化キー (MEK) を指定して、暗号化されたデータベースにアクセスできます。ドライバーは自動的に暗号文を復号し、プレーンテキストデータを返します。
MEK の生成
クライアントは、安全な非対称暗号化プロトコルを介して MEK をデータベースサーバーに送信します。このプロセスにより、サーバーとクライアントの両方が同じキーを共有することが保証され、対称暗号化を使用した安全なデータ送信が可能になります。
有効値: 16 バイトの 16 進数文字列 (長さ 32 文字)。
MEK は、クライアントが暗号化されたデータにアクセスすることを承認するルート認証情報です。セキュリティ上の理由から、暗号化されたデータベースは MEK を保持または管理しません。また、MEK を生成またはバックアップするサービスも提供しません。MEK は自分で生成する必要があります。MEK の保存と管理は、データベースのセキュリティにとって重大です。MEK を安全にバックアップすることを推奨します。
列暗号化構成で選択した [暗号化方式] に応じて、[KMS キー] を取得するか、[ローカルキー] を生成して、データベースを復号するための MEK として使用できます。
KMS 鍵
KMS キーを使用する場合、Key Management Service (KMS) が利用可能であることを確認してください。そうでない場合、常時暗号化クライアントドライバー EncJDBC は機能しません。
列暗号化構成で選択した KMS キー を含む KMS インスタンスのエンドポイントを取得する必要があります。また、対応する Alibaba Cloud アカウントまたは Resource Access Management (RAM) ユーザーの AccessKey ID と AccessKey Secret も必要です。このアカウントまたはユーザーは、クライアントが KMS キーを読み取れるように、KMS の復号権限を持っている必要があります。次のステップを実行します。
Alibaba Cloud アカウントまたは RAM ユーザーを使用してコンソールにログインします。
ローカル鍵
列暗号化構成の [暗号化方式] が [ローカルキー] に設定されている場合、MEK を生成する必要があります。例: 00112233445566778899aabbccddeeff。
一般的な生成方法には、パスワード生成ツールやプログラミング言語のランダム関数を使用する方法があります。
例:
Linux では、組み込みの OpenSSL ツールを使用し、
openssl rand -hex 16コマンドを実行してキーを生成できます。Windows では、OpenSSL ソフトウェアパッケージをインストールできます。
クライアントアクセス命令
Java 開発キット (JDK) 1.8 以降を使用してください。
クライアントで、データベース接続ドライバーを EncJDBC に変更し、データベース接続 URL を更新し、MEK を指定して、暗号化された列のプレーンテキストデータにアクセスできます。
1. 依存関係のインストール
Maven プロジェクトの pom.xml ファイルに次の依存関係を追加します。
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-cls-jdbc</artifactId>
<version>1.0.10-1</version>
</dependency>2. データベースに接続するための MEK の構成
次のメソッドを使用して MEK を構成できます: JDBC プロパティ構成、ファイル構成、および URL 構成。複数のメソッドを使用して Java Database Connectivity (JDBC) を構成する場合、次の優先順位が適用されます: JDBC プロパティ構成 > ファイル構成 > URL 構成。
URL 構成メソッドでは、アンパサンド (
&) を使用して複数のパラメーターを連結できます。次の構成および接続方法では、
MEKはクライアント上でローカルに処理され、エンベロープ暗号化を使用してサーバーに安全に送信されます。これにより、MEKが漏洩しないことが保証されます。
列暗号化構成の 暗号化方式 に基づいて、ローカルキーまたは KMS キーのいずれかを使用してデータベースに接続します。
KMS キーを使用してデータベースに接続する
セキュリティトークンサービス (STS) からの一時的なアクセス認証情報を使用して KMS で管理される MEK を取得する場合、STS ソフトウェア開発キット (SDK) を使用して一時的な STS トークンを取得できます。STS SDK の例については、「STS SDK の概要」をご参照ください。
ビジネスコードに AccessKey ペア (AccessKey ID と AccessKey Secret) をハードコーディングしないでください。この例では、システム環境変数を使用して AccessKey ペアを管理します。詳細については、「Linux、macOS、および Windows で環境変数を構成する」をご参照ください。
JDBC プロパティ構成
標準の JDBC を使用して接続する場合、Properties を介してカスタムユーザープロパティを設定できます。次の例は、この方法で JDBC を構成して実行する方法を示しています。
// エンドポイント (ホスト名)、ポート、データベースインスタンス名 (dbname)、ユーザー名、パスワードなどの接続情報を準備します。
// ...
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// システム環境変数から AccessKey ID と AccessKey Secret を取得します。
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// STS の一時的なアクセス認証情報を使用して KMS キーを読み取る場合は、取得したセキュリティトークンサービス (STS) トークンも提供する必要があります。
// String stsToken= "yourSecurityToken";
// KMS インスタンスのエンドポイント。インターネットアクセスにはパブリックエンドポイントを使用します。VPC アクセスにはインスタンス VPC エンドポイントを使用します。
String kmsEndpoint = "kms.cn-hangzhou.aliyuncs.com";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("ALIBABA_CLOUD_ACCESS_KEY_ID", accessKeyId);
props.setProperty("ALIBABA_CLOUD_ACCESS_KEY_SECRET", accessKeySecret);
props.setProperty("ALIBABA_CLOUD_KMS_ENDPOINT", kmsEndpoint);
// props.setProperty("ALIBABA_CLOUD_STS_TOKEN","stsToken");
// 以下は、RDS for MySQL データベースの接続 URL フォーマットです: "jdbc:mysql:encdb://%s:%s/%s"。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// 以下は、RDS for MySQL データベース用の EncJDBC ドライバーをロードします。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// データベース接続を取得します。
Connection connection = DriverManager.getConnection(dbUrl, props);
// ... クエリを開始 ...URL 構成
次の例に示すように、KMS キーを取得するためのパラメーターを URL に埋め込むことができます。
// エンドポイント (ホスト名)、ポート、データベースインスタンス名 (dbname)、ユーザー名、パスワードなどの接続情報を準備します。
// ...
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// システム環境変数から AccessKey ID と AccessKey Secret を取得します。
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// STS の一時的なアクセス認証情報を使用して KMS キーを読み取る場合は、取得した STS トークンも提供する必要があります。
// String stsToken= "yourSecurityToken";
// KMS インスタンスのエンドポイント。インターネットアクセスにはパブリックエンドポイントを使用します。VPC アクセスにはインスタンス VPC エンドポイントを使用します。
String kmsEndpoint = "kms.cn-hangzhou.aliyuncs.com";
// 以下は、RDS for MySQL データベースの接続 URL フォーマットです。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?ALIBABA_CLOUD_ACCESS_KEY_ID=%s&ALIBABA_CLOUD_ACCESS_KEY_SECRET=%s&ALIBABA_CLOUD_KMS_ENDPOINT=%s", hostname, port, dbname, accessKeyId,accessKeySecret,kmsEndpoint);
// STS トークンを使用します。
// String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?ALIBABA_CLOUD_ACCESS_KEY_ID=%s&ALIBABA_CLOUD_ACCESS_KEY_SECRET=%s&ALIBABA_CLOUD_KMS_ENDPOINT=%s&ALIBABA_CLOUD_STS_TOKEN=%s", hostname, port, dbname, accessKeyId,accessKeySecret,kmsEndpoint,stsToken);
// 以下は、RDS for MySQL データベース用の EncJDBC ドライバーをロードします。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// データベース接続を取得します。
Connection connection = DriverManager.getConnection(dbUrl, username, password);
// ... クエリを開始 ...ローカルキーを使用してデータベースに接続する
JDBC プロパティ構成
標準の JDBC を使用して接続する場合、Properties を介してカスタムユーザープロパティを設定できます。次の例は、この方法で JDBC を構成して実行する方法を示しています。
// エンドポイント (ホスト名)、ポート、データベースインスタンス名 (dbname)、ユーザー名、パスワードなどの接続情報を準備します。
// ...
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// 顧客マスターキー。
String mek = "00112233445566778899aabbccddeeff";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
// 以下は、RDS for MySQL データベースの接続 URL フォーマットです: "jdbc:mysql:encdb://%s:%s/%s"。RDS for PostgreSQL データベースの場合は、フォーマットを "jdbc:postgresql:encdb://%s:%s/%s" に置き換えます。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// 以下は、RDS for MySQL データベース用の EncJDBC ドライバーをロードします。RDS for PostgreSQL データベースの場合は、ドライバーを "com.aliyun.encdb.postgresql.jdbc.EncDriver" に置き換えます。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// データベース接続を取得します。
Connection connection = DriverManager.getConnection(dbUrl, props);
// ... クエリを開始 ...ファイル構成
必要な MEK などのパラメーターを構成ファイルからインポートできます。
ファイル構成メソッドは、ローカルキー MEK の構成にのみ適用されます。
プロジェクトで、property という名前の encJdbcConfigFile を設定し、その値を構成ファイルのパスに設定できます。このプロパティを設定しない場合、デフォルトで encjdbc.conf ファイルが使用されます。構成ファイルの内容は次のとおりです。
MEK=00112233445566778899aabbccddeeff構成ファイルは、次の 2 つの場所のいずれかに配置できます。
次の図に示すように、プロジェクトのリソースフォルダにファイルを配置します。

プログラムのランタイムディレクトリであるプロジェクトのルートディレクトリにファイルを配置します。
ファイルを構成した後、次の例に示すように、プログラムで追加の構成を行う必要はありません。
// エンドポイント (ホスト名)、ポート、データベースインスタンス名 (dbname)、ユーザー名、パスワードなどの接続情報を準備します。
// ...
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// 以下は、RDS for MySQL データベースの接続 URL フォーマットです: "jdbc:mysql:encdb://%s:%s/%s"。RDS for PostgreSQL データベースの場合は、フォーマットを "jdbc:postgresql:encdb://%s:%s/%s" に置き換えます。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// 以下は、RDS for MySQL データベース用の EncJDBC ドライバーをロードします。RDS for PostgreSQL データベースの場合は、ドライバーを "com.aliyun.encdb.postgresql.jdbc.EncDriver" に置き換えます。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// データベース接続を取得します。
Connection connection = DriverManager.getConnection(dbUrl, username, password);
// ... クエリを開始 ...URL 構成
次の例に示すように、MEK などのパラメーターを URL に埋め込むことができます。
// エンドポイント (ホスト名)、ポート、データベースインスタンス名 (dbname)、ユーザー名、パスワードなどの接続情報を準備します。
// ...
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// 顧客マスターキー。
String mek = "00112233445566778899aabbccddeeff";
// 以下は、RDS for MySQL データベースの接続 URL フォーマットです: "jdbc:mysql:encdb://%s:%s/%s?MEK=%s"。RDS for PostgreSQL データベースの場合は、フォーマットを "jdbc:postgresql:encdb://%s:%s/%s?MEK=%s" に置き換えます。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?MEK=%s", hostname, port, dbname, mek);
// 以下は、RDS for MySQL データベース用の EncJDBC ドライバーをロードします。RDS for PostgreSQL データベースの場合は、ドライバーを "com.aliyun.encdb.postgresql.jdbc.EncDriver" に置き換えます。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// データベース接続を取得します。
Connection connection = DriverManager.getConnection(dbUrl, username, password);
// ... クエリを開始 ...3. 暗号化された列のプレーンテキストデータをクエリする
データベースへの接続に成功したら、通常の JDBC クエリと同様にデータベース操作を実行できます。EncJDBC は、暗号化された列を自動的に復号し、プレーンテキストデータを返します。
サンプルコード:
// クエリを開始します。
// クエリ文を作成します。
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM your_table_name");
// 結果セットを走査します。
while (resultSet.next()) {
for (int i = 0; i < resultSet.getMetaData().getColumnCount(); i++) {
System.out.print(resultSet.getString(i + 1));
System.out.print("\t");
}
System.out.print("\n");
}完全なコード例
このセクションでは、JDBC プロパティ構成を使用してローカルキー MEK を設定する例を示します。[暗号文権限 (JDBC 復号)] 権限を持つデータベースアカウントを使用して、RDS for MySQL データベースの暗号化された列のプレーンテキストデータをクエリする方法を示します。
次の例のデータベース構成の詳細については、列の暗号化結果の検証にある「RDS MySQL データベース列の暗号化の例」をご参照ください。
この例では、Maven 3.9.9 と開発ツール IntelliJ IDEA Community Edition 2024.1.2 を使用します。
import java.sql.*;
import java.util.Properties;
public class EncryptedColumnAccess {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 次の接続情報 (エンドポイント (ホスト名)、ポート、データベースインスタンス名 (dbname)、ユーザー名、パスワードなど) をインスタンスの情報に置き換えます。
String hostname = "rm-******.mysql.rds.aliyuncs.com";
String port = "3306";
String dbname = "sddp_em_db";
String username = "sddp_em03";
String password = "******";
// これは単なる例です。より複雑なキーを使用することを推奨します。
String mek="00112233445566778899aabbccddeeff";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// EncJDBC ドライバーをロードします。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// データベース接続を取得します。
Connection connection = DriverManager.getConnection(dbUrl, props);
// クエリを開始します。
try {
// クエリ文を作成します。
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
// 結果セットを走査します。
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("username");
String phone = resultSet.getString("phone");
// テーブルスキーマに基づいて他のフィールドを処理します。
System.out.println("ID: " + id + ", Name: " + name + ", Phone: " + phone);
}
// リソースを閉じます。
resultSet.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}出力例:
