全部產品
Search
文件中心

ApsaraDB RDS:列加密驅動(JDBC)

更新時間:Mar 22, 2025

若需通過Java應用程式訪問資料庫中的加密列資料,您可以使用阿里雲提供的列加密驅動(JDBC)。在持有使用者密鑰的情況下,列加密驅動能夠自動完成密文資料的解密並返回明文資料,該過程對應用程式是透明的。應用程式只需配置幾行代碼,即可接入列加密能力。

前提條件

  • 已開通列加密,詳情請參見列加密

    說明

    開通列加密後,系統將預設在目標資料庫中安裝rds_encdb外掛程式。您可以通過執行SQL語句來查詢rds_encdb外掛程式的狀態:SELECT EXISTS (SELECT * FROM pg_extension WHERE extname = 'rds_encdb');

  • 已擷取加密資料庫串連資訊。您首先需要擷取加密資料庫的串連資訊,如網域名稱(host)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等。執行個體內網或外網地址擷取方式請參見查看或修改串連地址和連接埠

  • 已為資料庫使用者配置了列加密的密文許可權(JDBC解密),詳情請參見修改資料庫帳號許可權

注意事項

  • 請儲存好您設定的主要金鑰MEK

  • Java使用JDK 1.8或以上版本。

操作步驟

說明

本文以Maven構建Java專案為例。

步驟一:配置Maven依賴

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

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

步驟二:配置URL和MEK

通過JDBC訪問資料庫加密列的資料前,需要配置相關參數,包括MEK(主要金鑰)、URL(資料庫連接資訊)。

參數

取值樣本(字串類型)

說明

MEK

00112233445566778899aabbccddeeff

使用者主要金鑰,由使用者自訂。

  • 常見的產生方法有:密碼產生工具(如openssl, openssl rand -hex 16)、程式設計語言中的random函數、或者從第三方Key Management Service(KMS)擷取。

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

警告

使用者主要金鑰是您訪問加密資料的根憑據,出於安全考慮,資料庫不持有並管理您的主要金鑰,也不提供使用者主要金鑰的產生和備份服務,您需要自行產生使用者主要金鑰。一旦您丟失密鑰,將無法再訪問已有的資料。因此我們建議您妥善備份使用者主要金鑰。

URL

jdbc:postgresql:encdb://%s:%s/%s

使用列加密驅動時,請將URL修改為以jdbc:postgresql:encdb://開頭。

配置MEK

以下將介紹三種配置MEK的方法。如果您的JDBC同時配置了兩種以上的方式,優先順序順序為:JDBC properties配置 > 檔案配置 > URL配置。

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

  • 以下三種串連方式,MEK均在用戶端本地進行處理、並以安全方式分發(信封加密)到服務端,始終保證MEK不泄露。

JDBC properties配置

標準的JDBC在建立串連時,可以通過Properties配置使用者自訂屬性。例如:

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

String mek=****;

Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);


String dbUrl = String.format("jdbc:postgresql:encdb://%s:%s/%s", hostname, port, dbname);
Connection connection = DriverManager.getConnection(dbUrl, props);

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

支援通過設定檔匯入所需的參數,例如MEK。在專案中設定一個名為encJdbcConfigFile的屬性,將其值指定為設定檔的路徑。若未設定,該屬性將預設使用 encjdbc.conf 檔案。

設定檔的內容如下:

MEK=****

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

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

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

通過檔案配置MEK後,程式中無需額外配置,例如:

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

String dbUrl = String.format("jdbc:postgresql:encdb://%s:%s/%s", hostname, port, dbname);
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// ... 發起查詢 ...
URL配置

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

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

String mek=****;

String dbUrl = String.format("jdbc:postgresql:encdb://%s:%s/%s?MEK=%s", hostname, port, dbname, mek);
Connection connection = DriverManager.getConnection(dbUrl, username, password);

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

完整範例程式碼

如下範例程式碼以JDBC properties配置MEK的方式為例。在進行JDBC訪問之前,已完成目標資料庫的列加密設定。

package org.example;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

public class Main {
    public static void main(String[] args) throws SQLException {
        // 以下串連資訊(hostname、port、dbname、username、password)需要根據實際情況更新
        String hostname = "pgm-****.pg.rds.aliyuncs.com"; // 執行個體串連地址,請更新為實際值
        String port = "5432"; // 資料庫連接埠,請更新為實際值
        String dbname = "testdb"; // 資料庫名稱,請更新為實際值
        String username = "user"; // 資料庫使用者名稱,請更新為實際具有密文許可權(JDBC解密)的使用者
        String password = "password"; // 資料庫使用者名稱的密碼
        
        // 樣本密鑰,建議使用複雜度更高的密鑰以確保安全
        String MEK = "00112233445566778899aabbccddeeff";
        
       // 建立資料庫連接屬性
        Properties props = new Properties();
        props.setProperty("user", username);
        props.setProperty("password", password);
        props.setProperty("MEK", MEK);

        // 格式化資料庫連接URL
        String dbUrl = String.format("jdbc:postgresql:encdb://%s:%s/%s", hostname, port, dbname);

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

        // 執行查詢以擷取測試表中的資料
        ResultSet rs = connection.createStatement().executeQuery("SELECT * FROM test_table");
        while (rs.next()) {
            for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { // 列索引從1開始
                System.out.print(rs.getString(i) + "\t");
            }
            System.out.println(); // 換行
        }

        // 關閉資源
        rs.close();  // 關閉結果集
        connection.close(); // 關閉串連
    }
}