全部產品
Search
文件中心

PolarDB:整合EncJDBC

更新時間:Jan 14, 2026

為了支援您的Java業務系統實現零改造與一鍵式接入,全密態資料庫功能推出了相應的全密態用戶端驅動JDBC(即EncJDBC)。EncJDBC能夠自動完成密文資料的解密,並返回明文資料,整個過程對應用程式而言是透明的,業務應用僅需幾行配置即可接入全密態資料庫,現有業務代碼無需進行任何修改。

方案架構

全密態資料庫是一套基於資料庫代理(Proxy)的動態加解密方案。其核心邏輯是在查詢結果返回給用戶端的過程中,由代理層對預先配置的敏感欄位進行加密。用戶端應用程式需配合專用的 EncJDBC 驅動,在接收到資料後進行透明解密。

工作流程與角色許可權

  1. 查詢請求:用戶端應用通過EncJDBC驅動向PolarDB叢集地址發起標準SQL查詢。

  2. 代理處理:資料庫代理(Proxy)接收請求,轉寄至後端資料庫核心執行。

  3. 動態加密:在查詢結果返回途中,代理層檢查是否命中預設的加密策略。如果命中,則使用使用者指定的密鑰(通過KMS或自持)對結果集中的敏感欄位進行加密。

  4. 資料返回:加密後的結果集返回給用戶端。

  5. 透明解密:用戶端的EncJDBC驅動自動對密文資料進行解密,應用程式擷取到明文資料,整個過程對業務代碼透明。

根據資料庫帳號的角色,查詢結果會有不同表現:

  • 超級管理員:查詢結果始終為明文,不受加密策略影響,便於資料庫管理與審計。

  • 普通使用者:查詢結果為密文,需配合使用EncJDBC驅動和正確的密鑰才能在用戶端解密資料。

  • 其他使用者:查詢結果為密文,且無法解密。

使用限制

實施前,需瞭解以下關鍵限制,以評估其是否符合業務與技術架構要求。

  • 串連地址要求:加密規則僅在通過叢集地址自訂地址串連時生效。直接連接主地址將繞過代理,導致加密功能失效。

  • 密鑰管理:使用自持密鑰時,暫不支援更新密鑰且存在丟失和泄露風險。密鑰一旦丟失,對應的加密資料將無法解密,需建立嚴格的安全流程來管理密鑰。

  • JDK版本:需使用1.8或以上版本。

使用KMS密鑰

步驟一:配置KMS存取權限

  1. 擷取存取金鑰:擷取RAM使用者的AccessKeyIdAccessKeySecret,以便應用程式能夠擷取KMS託管的MEK。

    1. 已有合適的RAM使用者:若您已有適用的RAM使用者以訪問KMS,則可直接使用該使用者。

    2. 無合適的RAM使用者:若無合適的RAM使用者,請前往RAM 控制台,進入身份管理 > 使用者頁面,單擊建立使用者,並按照頁面指引完成使用者建立。

  2. RAM使用者授權

    1. 前往RAM 控制台,進入許可權管理 > 權限原則頁面,單擊建立權限原則。切換至指令碼編輯,複製下述內容並單擊確定。填寫策略名稱稱,完成建立。

      {
          "Version": "1",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "KMS:Decrypt",
                  "Resource": "*"
              }
          ]
      }
    2. 返回RAM 控制台,進入身份管理 > 使用者頁面,找到目標RAM使用者,單擊操作列的添加許可權,並授予其剛建立的權限原則。以便於PolarDB可動態解密資料。

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

    • VPC地址(預設):KMS執行個體中的密鑰預設僅允許VPC網路訪問,您可以在KMS的執行個體管理頁面,選擇執行個體所在地區,找到目標KMS執行個體,單擊操作列的詳情,然後在基本資料頁簽,查看執行個體VPC地址。

    • 公網地址:若您需要通過公網存取金鑰,則需要在RD多帳號頁簽下開啟公網存取權限。開啟後,可在基本資料頁簽,查看公網地址

步驟二:安裝依賴

您需要在自己的Maven專案設定檔pom.xml中加入以下依賴項。

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-cls-jdbc</artifactId>
    <version>1.0.10-1</version>
</dependency>
說明

在添加Maven依賴時請根據實際使用情境替換version的值。您可以在官網上查看aliyun-cls-jdbc的最新版本。

步驟三:配置MEK串連資料庫

您可以通過JDBC properties屬性、檔案以及URL三種方式來配置MEK。若您的JDBC同時配置了兩種或更多方法,則優先順序順序為:JDBC properties配置 > 檔案配置 > URL配置。

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

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

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

JDBC properties配置

標準的JDBC在建立串連時,可以通過Properties對象設定使用者自訂屬性。

樣本

// 準備好串連地址(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 = "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");

// 下面是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 = "your-kms-endpoint";

// 下面是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查詢一樣操作資料庫。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");
}

附錄:完整程式碼範例

說明

本樣本使用的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 = "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 = "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");

        // MySQL版資料庫的串連URL格式"jdbc:mysql:encdb://%s:%s/%s"。
        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();
        }
    }
}

使用本地密鑰

步驟一:產生MEK

警告

MEK是您授權用戶端訪問加密資料的根憑據。出於安全考慮,加密資料庫不持有並管理您的MEK,也不提供MEK的產生和備份服務,您需要自行產生MEK。MEK的儲存和管理對資料庫的安全性非常重要。因此建議您妥善備份MEK。

MEK:由用戶端通過安全的非對稱式加密協議傳輸給資料庫服務端,使服務端與用戶端具有相同的密鑰,從而通過對稱式加密安全傳輸資料。

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

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

樣本

  • Linux系統內建OpenSSL工具,執行openssl rand -hex 16,產生密鑰。

    # 使用 OpenSSL 產生一個安全的隨機密鑰
    openssl rand -hex 16
    # 輸出樣本: 11ce9a9489fab7355cf710837cea5d5b
  • Windows系統,請安裝OpenSSL軟體包

步驟二:安裝依賴

您需要在自己的Maven專案設定檔pom.xml中加入以下依賴項。

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-cls-jdbc</artifactId>
    <version>1.0.10-1</version>
</dependency>
說明

在添加Maven依賴時請根據實際使用情境替換version的值。您可以在官網上查看aliyun-cls-jdbc的最新版本。

步驟三:配置MEK串連資料庫

您可以通過JDBC properties屬性、檔案以及URL三種方式來配置MEK。若您的JDBC同時配置了兩種或更多方法,則優先順序順序為:JDBC properties配置 > 檔案配置 > URL配置。

說明

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

JDBC properties配置

標準的JDBC在建立串連時,可以通過Properties對象設定使用者自訂屬性。

樣本

// 準備好串連地址(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"。
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);

// ... 發起查詢 ...
檔案配置
說明

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

支援通過設定檔匯入參數,以配置所需的MEK等參數。您可以在專案中設定一個名為encJdbcConfigFile的屬性,將其值設定為設定檔的路徑(預設時,系統將預設使用encjdbc.conf檔案)。設定檔的內容如下:

MEK=00112233445566778899aabbccddeeff

樣本

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

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

      image

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

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

    // 準備好串連地址(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"
    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, 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"。
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?MEK=%s", hostname, port, dbname, mek);

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

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

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

步驟四:查詢加密列的明文資料

串連資料庫成功後,可以像普通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");
}

附錄:完整程式碼範例

說明

本樣本使用的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 = "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"。
        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();
        }
    }
}

常見問題

整合EncJDBC時,運行報錯Code: Forbidden.KeyNotFound;Message: code: 404, The specified Key is not found.應如何處理?

請檢查您應用程式中,KMS執行個體訪問地址是否設定正確。

  • 檢查應用程式環境:KMS執行個體訪問地址區分VPC地址與公網地址。

    • VPC地址(預設):KMS執行個體中的密鑰預設僅允許VPC網路訪問,您可以在KMS的執行個體管理頁面,選擇執行個體所在地區,找到目標KMS執行個體,單擊操作列的詳情,然後在基本資料頁簽,查看執行個體VPC地址。

    • 公網地址:若您需要通過公網存取金鑰,則需要在RD多帳號頁簽下開啟公網存取權限。開啟後,可在基本資料頁簽,查看公網地址

  • 檢查KMS執行個體地區

    • 請根據您KMS執行個體所在地區調整訪問地址。例如,華東1(杭州)公網地址應為kms.cn-hangzhou.aliyuncs.com,華北2(北京)公網地址應為kms.cn-beijing.aliyuncs.com

整合EncJDBC時,運行報錯Code:UnsupportedOperation;Message: code: 400, This action is not supported.應如何處理?

可能的原因如下,請逐一進行排查:

  • 您可能使用的並非KMS的使用者主要金鑰,而是預設密鑰中的主要金鑰。

    說明

    您的預設密鑰中的主要金鑰只能用於雲產品服務端加密,不能用於您的用戶端資料加密。如果您有用戶端資料加密的訴求(全密態資料庫),請通過建立執行個體購買主要金鑰(軟體)或者主要金鑰(硬體)

  • KMS執行個體沒有開通公網存取權限。

整合EncJDBC時,運行報錯Code:Forbidden.NoPermission;Message: code: 403, This operation for XXX is forbidden by permission system.應如何處理?

您的存取金鑰(AccessKeyIdAccessKeySecret)可能沒有KMS的存取權限,請授予其KMS:Decrypt許可權,以便於PolarDB可動態解密資料。

  1. 前往RAM 控制台,進入許可權管理 > 權限原則頁面,單擊建立權限原則。切換至指令碼編輯,複製下述內容並單擊確定。填寫策略名稱稱,完成建立。

    {
        "Version": "1",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "KMS:Decrypt",
                "Resource": "*"
            }
        ]
    }
  2. 返回RAM 控制台,進入身份管理 > 使用者頁面,找到目標RAM使用者,單擊操作列的添加許可權,並授予其剛建立的權限原則。以便於PolarDB可動態解密資料。