全部產品
Search
文件中心

Data Security Center:整合EncJDBC

更新時間:Jan 22, 2026

配置RDS MySQL版、RDS PostgreSQL版、PolarDB MySQL版或PolarDB PostgreSQL版資料庫表中敏感性資料列加密後,如果希望通過Java應用訪問這些加密列的明文,可使用EncJDBC驅動串連資料庫。本文介紹如何使用EncJDBC串連資料庫並訪問加密列的明文資料。

前提條件

  • 已為目標資料庫配置列加密能力,並設定目標資料庫帳號的密文許可權為密文权限(JDBC解密)。設定資料庫列加密的具體操作和帳號許可權的詳細說明,請參見設定資料庫列加密

  • 已擷取加密資料庫串連資訊:串連地址、連接埠、資料庫名稱、資料庫帳號、密碼。

背景資訊

列加密功能允許使用者對資料庫中的特定敏感列實施動態輸出保護,從而提升資料安全性。啟用該功能後,系統會根據資料庫帳號的權限原則控制查詢結果:

  • 具備明文权限的帳號可直接查看未經處理資料;

  • 配置為密文权限(JDBC解密)的帳號將收到加密後的密文,但可通過阿里雲提供的全密態 JDBC 驅動(EncJDBC)並提供與加密策略一致的主加密金鑰(Master Encryption Key,簡稱 MEK)自動還原為明文;

  • 而配置為密文权限(无解密权限)的帳號則只能看到密文,且無法以任何形式解密。

該機制確保敏感性資料在輸出環節得到有效保護,即使資料被匯出或截獲,也無法被未授權方讀取。

產生MEK

當您選擇本地密鑰方式為某列啟用列加密功能時,DSC 列加密網關會在查詢結果返回用戶端前,使用一個受控金鑰組敏感欄位進行加密處理。此時,除具有明文許可權的帳號外,其他帳號查詢該列將收到加密後的密文資料。

因此,若您希望後續通過密文許可權(JDBC解密)帳號正常訪問明文,請務必在首次配置列加密時主動提供並記錄您自己的 MEK。只有使用與加密策略一致的 MEK,EncJDBC 驅動才能在用戶端正確解密查詢結果中的密文欄位。

  • 取值範圍:長度為16位元組的16進位字串,且長度為32個字元。

  • MEK的作用:MEK 是您授權 EncJDBC 用戶端解密查詢結果中密文欄位的根憑據。它用於保護實際用於加密查詢結果的密鑰。

  • 安全責任:阿里雲不會儲存、備份或託管您的 MEK。請務必通過安全的密鑰管理方案(如 KMS等)妥善保管。

  • 重要警告:一旦丟失 MEK,所有通過該策略加密的歷史查詢結果將永久無法解密

您需要根據資料庫列加密配置中選擇的加密方式,擷取KMS密钥或產生本地密钥作為MEK來解密對應資料庫。

KMS密鑰

重要

使用KMS密鑰時,請確保KMS服務可用。否則,全密態用戶端驅動EncJDBC無法使用。

您需要擷取資料庫列加密配置中選擇的KMS密鑰所屬KMS執行個體的訪問地址,以及對應阿里雲帳號或RAM使用者(必須具備KMS解密許可權)的存取金鑰AccessKeyId和AccessKeySecret,以便通過用戶端讀取該KMS密鑰。具體操作如下:

  1. 使用阿里雲帳號RAM使用者登入控制台。

  2. 如果是RAM使用者,需要授予RAM使用者KMS解密許可權。

    1. 建立自訂權限原則。策略內容如下:

      {
          "Version": "1",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "KMS:Decrypt",
                  "Resource": "*"
              }
          ]
      }
    2. 將建立的自訂權限原則授予指定的RAM使用者。具體操作,請參見管理RAM使用者的許可權

  3. 擷取KMS執行個體訪問地址。

    • KMS執行個體中的密鑰預設僅允許VPC網路訪問,您可以在KMS的執行個體管理頁面,找到目標KMS執行個體,單擊操作列的详情,然後在基本信息頁簽,查看執行個體VPC地址。

    • 如果需要通過公網存取金鑰,需要開啟公網訪問後查看公網地址。具體操作,請參見開啟公網訪問

  4. 擷取存取金鑰。

    您需要在建立阿里雲帳號或RAM使用者的AccessKey時,儲存AccessKeyId和AccessKeySecret。具體操作,請參見建立AccessKey

本地密鑰

資料庫列加密配置中加密方式本地密钥時,您需要產生一個MEK。例如,00112233445566778899aabbccddeeff。

常見的產生方法有:密碼產生工具或程式設計語言中的random函數。

例如:

  • 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 properties配置、檔案配置和URL配置。如果您的JDBC同時配置了兩種以上的方法,優先順序順序為:JDBC properties配置 > 檔案配置 > URL配置。

說明
  • URL配置方式中,多個參數可以用&進行拼接。

  • 以下配置和串連方式,MEK均在用戶端本地進行處理,並以安全方式(信封加密)發送到服務端,保證MEK不泄露。

根據資料庫列加密配置中的加密方式,選擇通過本地密鑰或KMS密鑰串連資料庫。

通過KMS密鑰串連資料庫

重要
  • 如果使用STS臨時訪問憑證擷取KMS託管的MEK,您可以使用STS SDK擷取臨時憑據STS Token。STS SDK樣本,請參見STS SDK概覽

  • 不能直接將存取金鑰(AccessKeyId和AccessKeySecret)寫入程式碼在業務代碼中,本樣本使用配置系統內容變數的方式管理存取金鑰。具體內容,請參見在Linux、macOS和Windows系統配置環境變數

JDBC properties配置

標準的JDBC在串連時,可以通過Properties設定使用者自訂屬性。以下是通過這種方式配置JDBC屬性並運行JDBC的例子:

// 準備好串連地址(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊。
// ...

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安全性權杖(SecurityToken)。
// 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");



// 下面是MySQL版資料庫的串連URL格式"jdbc:mysql:encdb://%s:%s/%s"。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);

// 下面是MySQL版資料庫的載入 EncJDBC 驅動。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");

// 擷取資料庫連接。
Connection connection = DriverManager.getConnection(dbUrl, props);

// ... 發起查詢 ...

URL配置

支援通過URL連結中嵌入擷取KMS密鑰的參數。如下面所示:

// 準備好串連地址(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊。
// ...
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安全性權杖(SecurityToken)。
// String stsToken= "yourSecurityToken";

// KMS執行個體訪問地址,開啟公網訪問使用公網地址。在VPC網路訪問,使用執行個體VPC地址。
String kmsEndpoint = "kms.cn-hangzhou.aliyuncs.com";

// 下面是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 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);

// 下面是MySQL版資料庫的載入 EncJDBC 驅動。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");

// 擷取資料庫連接。
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// ... 發起查詢 ...

通過本地密鑰串連資料庫

JDBC properties配置

標準的JDBC在串連時,可以通過Properties設定使用者自訂屬性。以下是通過這種方式配置JDBC屬性並運行JDBC的例子:

// 準備好串連地址(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊。
// ...

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);

// 下面是MySQL版資料庫的串連URL格式"jdbc:mysql:encdb://%s:%s/%s"。PostgreSQL版資料庫的串連URL格式需替換為"jdbc:postgresql:encdb://%s:%s/%s"。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);

// 下面是MySQL版資料庫的載入 EncJDBC 驅動。PostgreSQL版資料庫的載入 EncJDBC 驅動替換為"com.aliyun.encdb.postgresql.jdbc.EncDriver"。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");

// 擷取資料庫連接。
Connection connection = DriverManager.getConnection(dbUrl, props);

// ... 發起查詢 ...

檔案配置

支援通過設定檔來匯入參數,配置需要的MEK等參數。

說明

檔案配置方式僅適用配置本地密鑰MEK。

您可以在專案中設定一個名為encJdbcConfigFileproperty,將值設定為設定檔路徑即可(預設時,預設使用encjdbc.conf的檔案)。設定檔的內容如下:

MEK=00112233445566778899aabbccddeeff

您可以通過以下兩種方式放置設定檔的位置:

  • 將檔案放入專案中的resources目錄下,如下圖所示:

    image

  • 將檔案放入專案根目錄,即程式的運行時目錄。

通過檔案配置方式,在做完檔案配置後,您可以不用在程式中做額外的配置,如下面所示:

// 準備好串連地址(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊。
// ...
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";

// 下面是MySQL版資料庫的串連URL格式"jdbc:mysql:encdb://%s:%s/%s"。PostgreSQL版資料庫的串連URL格式需替換為"jdbc:postgresql:encdb://%s:%s/%s"。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);

// 下面是MySQL版資料庫的載入 EncJDBC 驅動。PostgreSQL版資料庫的載入 EncJDBC 驅動替換為"com.aliyun.encdb.postgresql.jdbc.EncDriver"。
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");

// 擷取資料庫連接。
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// ... 發起查詢 ...

URL配置

支援通過URL連結中嵌入MEK等參數。如下面所示:

// 準備好串連地址(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊。
// ...
String hostname = "your-hostname";
String port = "your-port";
String dbname = "your-database-name";
String username = "your-username";
String password = "your-password";
 // 使用者主要金鑰。
String mek = "00112233445566778899aabbccddeeff";

// 下面是MySQL版資料庫的串連URL格式"jdbc:mysql:encdb://%s:%s/%s?MEK=%s"。PostgreSQL版資料庫的串連URL格式需替換為"jdbc:postgresql:encdb://%s:%s/%s?MEK=%s"。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?MEK=%s", hostname, port, dbname, mek);

// 下面是MySQL版資料庫的載入 EncJDBC 驅動。PostgreSQL版資料庫的載入 EncJDBC 驅動替換為"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 < rs.getMetaData().getColumnCount(); i++) {
        System.out.print(rs.getString(i + 1));
        System.out.print("\t");
    }
    System.out.print("\n");
}

完整程式碼範例

以JDBC properties配置本地密鑰MEK為例,使用具備密文权限(JDBC解密)的資料庫帳號查詢某RDS 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 {
        // 以下串連地址(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊需要更新為您的執行個體資訊。
        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();
        }
    }
}

輸出結果樣本:

image