To support seamless integration for your Java applications without code modifications, the PolarDB Always-confidential feature provides a dedicated client driver, Encrypted Java Database Connectivity (EncJDBC). EncJDBC automatically decrypts ciphertext and returns plaintext data. This process is transparent to the application. Your application can connect to PolarDB Always-confidential with just a few lines of configuration, and no changes to your existing business code are required.
Solution architecture
PolarDB Always-confidential is a dynamic encryption and decryption solution based on a database proxy. The core logic is that the proxy layer encrypts pre-configured sensitive fields in the query results before returning them to the client. The client application must use the dedicated EncJDBC driver to transparently decrypt the data upon receipt.
Workflow and role permissions
Query request: The client application sends a standard SQL query to the PolarDB cluster endpoint through the EncJDBC driver.
Proxy processing: The database proxy receives the request and forwards it to the backend database kernel for execution.
On-the-fly encryption: As the query results are returned, the proxy layer checks whether they match a pre-set encryption policy. If a match is found, the sensitive fields in the result set are encrypted using the key that you specify from KMS or a self-managed key.
Data return: The encrypted result set is returned to the client.
Transparent decryption: The EncJDBC driver on the client automatically decrypts the ciphertext. The application receives plaintext data, and the entire process is transparent to the business code.
Query results vary based on the role of the database account
Super administrator: Query results are always in plaintext and are not affected by encryption policies. This is useful for database management and auditing.
Regular user: Query results are ciphertext. You must use the EncJDBC driver and the correct key to decrypt data on the client.
Other users: Query results are ciphertext and cannot be decrypted.
Limits
Before you implement this feature, review the following limits to assess whether the feature meets your business and technical architecture requirements.
Endpoint requirement: Encryption rules take effect only when you connect using a cluster endpoint or a custom endpoint. Connecting directly to the primary endpoint bypasses the proxy, which disables the encryption feature.
Key management: When you use a self-managed key, key rotation is not supported. You also risk key loss or leakage. If a key is lost, the corresponding encrypted data cannot be decrypted. You must establish strict security procedures to manage keys.
JDK version: You must use JDK 1.8 or later.
Use a KMS key
Step 1: Configure KMS access permissions
Obtain an AccessKey pair: Obtain the
AccessKey IDandAccessKey secretof a RAM user. This allows the application to obtain the master encryption key (MEK) that is managed by KMS.If you already have a suitable RAM user to access KMS, you can use that user.
If you do not have a suitable RAM user, go to the RAM console. In the navigation pane on the left, choose . Click Create User and follow the on-screen instructions to create a user.
Grant permissions to the RAM user
Go to the RAM console. On the page, click Create Access Policy. Switch to the script editor, copy the following content, and click OK. Enter a policy name and complete the creation.
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "KMS:Decrypt", "Resource": "*" } ] }In the RAM console, go to the page. Find the target RAM user, click Add Permissions in the Actions column, and grant it the newly created access policy. This allows PolarDB to dynamically decrypt data.
Step 2: Install dependencies
Add the following dependency to the pom.xml file of your Maven project.
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-cls-jdbc</artifactId>
<version>1.0.10-1</version>
</dependency>When you add the Maven dependency, replace the value of version as needed. You can check for the latest version of aliyun-cls-jdbc on the official website.
Step 3: Configure the MEK to connect to the database
You can configure the MEK using JDBC properties, a file, or a URL. If you configure your JDBC using two or more methods, the priority is as follows: JDBC properties configuration > File configuration > URL configuration.
In the following configuration and connection methods, the
MEKis processed locally on the client and sent to the server using a secure method (envelope encryption) to ensure that theMEKis not leaked.Do not hard code the AccessKey pair (
AccessKey IDandAccessKey secret) in your business code. This example uses system environment variables to manage the AccessKey pair. For more information, see Configure environment variables on Linux, macOS, and Windows systems.To use a temporary STS access credential to obtain the MEK that is managed by KMS, you can use an STS SDK to obtain a temporary credential, the Security Token Service (STS) token. For STS SDK examples, see Overview of STS SDKs.
JDBC properties configuration
When a standard JDBC connection is established, you can set custom attributes using a Properties object.
Example
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Get the AccessKey ID and AccessKey secret from environment variables.
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// If you use a temporary STS access credential to read the KMS key, you also need to fill in the obtained Security Token.
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for public network access. Use the instance VPC endpoint for access within a VPC network.
String kmsEndpoint = "your-kms-endpoint";
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");
// The following is the connection URL format for a MySQL database: "jdbc:mysql:encdb://%s:%s/%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// The following loads the EncJDBC driver for a MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// ... Initiate a query ...URL configuration
You can embed the parameters for obtaining the KMS key in the URL.
Example
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Get the AccessKey ID and AccessKey secret from environment variables.
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// If you use a temporary STS access credential to read the KMS key, you also need to fill in the obtained Security Token.
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for public network access. Use the instance VPC endpoint for access within a VPC network.
String kmsEndpoint = "your-kms-endpoint";
// The following is the connection URL format for a MySQL database.
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);
// Use an STS token.
// 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);
// The following loads the EncJDBC driver for a MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, username, password);
// ... Initiate a query ...Step 4: Query plaintext data from encrypted columns
After you successfully connect to the database, you can perform database operations as you would with a regular JDBC query. EncJDBC automatically decrypts encrypted columns and returns plaintext data.
Example
// Create a query statement.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM your_table_name");
// Traverse the result set.
while (resultSet.next()) {
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
System.out.print(rs.getString(i + 1));
System.out.print("\t");
}
System.out.print("\n");
}Appendix: Complete code example
This example uses Maven version 3.9.9 and the IntelliJ IDEA Community Edition 2024.1.2 development tool.
import java.sql.*;
import java.util.Properties;
public class EncryptedColumnAccess {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// Update the following connection information with your instance details, such as endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Get the AccessKey ID and AccessKey secret from environment variables.
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// If you use a temporary STS access credential to read the KMS key, you also need to fill in the obtained Security Token.
// String stsToken= "yourSecurityToken";
// For the KMS instance endpoint, use the public endpoint for public network access. Use the instance VPC endpoint for access within a VPC network.
String kmsEndpoint = "your-kms-endpoint";
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");
// The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// Load the EncJDBC driver.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// Initiate a query.
try {
// Create a query statement.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
// Traverse the result set.
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("username");
String phone = resultSet.getString("phone");
// Process other fields based on your table schema.
System.out.println("ID: " + id + ", Name: " + name + ", Phone: " + phone);
}
// Close resources.
resultSet.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}Use a local key
Step 1: Generate an MEK
The master encryption key (MEK) is the root credential that you use to authorize clients to access encrypted data. For security reasons, the encrypted database does not hold or manage your MEK. It also does not provide MEK generation or backup services. You must generate the MEK yourself. The storage and management of the MEK are critical to database security. We recommend that you back up your MEK properly.
MEK: The MEK is transmitted from the client to the database server using a secure asymmetric key encryption protocol. This allows the server and client to share the same key for secure data transmission through symmetric encryption.
Valid value: a 16-byte hexadecimal string that is 32 characters in length. For example, 00112233445566778899aabbccddeeff.
Common generation methods: You can use password generation tools or the random function in a programming language.
Example
On Linux, you can use the built-in OpenSSL tool. Run
openssl rand -hex 16to generate a key.# Use OpenSSL to generate a secure random key openssl rand -hex 16 # Example output: 11ce9a9489fab7355cf710837cea5d5bOn Windows, you can install the OpenSSL package.
Step 2: Install dependencies
Add the following dependency to the pom.xml file of your Maven project.
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-cls-jdbc</artifactId>
<version>1.0.10-1</version>
</dependency>When you add the Maven dependency, replace the value of version as needed. You can check for the latest version of aliyun-cls-jdbc on the official website.
Step 3: Configure the MEK to connect to the database
You can configure the MEK using JDBC properties, a file, or a URL. If you configure your JDBC using two or more methods, the priority is as follows: JDBC properties configuration > File configuration > URL configuration.
In the following configuration and connection methods, the MEK is processed locally on the client and sent to the server using a secure method (envelope encryption) to ensure that the MEK is not leaked.
JDBC properties configuration
When a standard JDBC connection is established, you can set custom attributes using a Properties object.
Example
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Customer master key.
String mek = "00112233445566778899aabbccddeeff";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
// The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// Load the EncJDBC driver for a MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// ... Initiate a query ...File configuration
The file configuration method is applicable only to configuring a local MEK.
You can import the required MEK and other parameters from a configuration file. In your project, set a property named encJdbcConfigFile and set its value to the path of the configuration file. If you do not specify a path, the system uses the encjdbc.conf file by default. The following code provides the content of the configuration file:
MEK=00112233445566778899aabbccddeeffExample
You can specify the location of the configuration file in one of the following two ways:
Place the file in the resources directory of your project, as shown in the following figure:

Place the file in the root directory of the project, which is the runtime directory of the program.
After you configure the file, you do not need to make additional configurations in your program, as shown in the following code:
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password. String hostname = "your-hostname"; String port = "your-port"; String dbname = "your-database-name"; String username = "your-username"; String password = "your-password"; // The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s". String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname); // Load the EncJDBC driver for a MySQL database. Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver"); // Get the database connection. Connection connection = DriverManager.getConnection(dbUrl, username, password); // ... Initiate a query ...
URL configuration
You can embed the MEK and other parameters in the URL.
Example
// Prepare connection information such as the endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// Customer master key.
String mek = "00112233445566778899aabbccddeeff";
// The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s?MEK=%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?MEK=%s", hostname, port, dbname, mek);
// Load the EncJDBC driver for a MySQL database.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, username, password);
// ... Initiate a query ...Step 4: Query plaintext data from encrypted columns
After you successfully connect to the database, you can perform database operations as you would with a regular JDBC query. EncJDBC automatically decrypts encrypted columns and returns plaintext data.
Example
// Create a query statement.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM your_table_name");
// Traverse the result set.
while (resultSet.next()) {
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
System.out.print(rs.getString(i + 1));
System.out.print("\t");
}
System.out.print("\n");
}Appendix: Complete code example
This example uses Maven version 3.9.9 and the IntelliJ IDEA Community Edition 2024.1.2 development tool.
import java.sql.*;
import java.util.Properties;
public class EncryptedColumnAccess {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// Update the following connection information with your instance details, such as endpoint (hostname), port, database instance name (dbname), username, and password.
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
// This is just an example. We recommend using a more complex key.
String mek="00112233445566778899aabbccddeeff";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
// The connection URL format for a MySQL database is "jdbc:mysql:encdb://%s:%s/%s".
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
// Load the EncJDBC driver.
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
// Get the database connection.
Connection connection = DriverManager.getConnection(dbUrl, props);
// Initiate a query.
try {
// Create a query statement.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
// Traverse the result set.
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("username");
String phone = resultSet.getString("phone");
// Process other fields based on your table schema.
System.out.println("ID: " + id + ", Name: " + name + ", Phone: " + phone);
}
// Close resources.
resultSet.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}